<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
	<meta name="theme-color" content="#33474d">
	<title>失落的乐章</title>
	<link rel="stylesheet" href="/css/style.css" />
	
      <link rel="alternate" href="/atom.xml" title="失落的乐章" type="application/atom+xml">
    
</head>

<body>

	<header class="header">
		<nav class="header__nav">
			
				<a href="/archives" class="header__link">Archive</a>
			
				<a href="/tags" class="header__link">Tags</a>
			
				<a href="/atom.xml" class="header__link">RSS</a>
			
		</nav>
		<h1 class="header__title"><a href="/">失落的乐章</a></h1>
		<h2 class="header__subtitle">技术面前，永远都是学生。</h2>
	</header>

	<main>
		
	<span class="different-posts different-posts_earlier">📖 <a href="/page/30">earlier posts</a> 📖</span>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/7. MongoDBPHP 扩展/">MongoDBPHP 扩展</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<h2 id="Linux上安装-MongoDB-PHP扩展"><a href="#Linux上安装-MongoDB-PHP扩展" class="headerlink" title="Linux上安装 MongoDB PHP扩展"></a>Linux上安装 MongoDB PHP扩展</h2><h3 id="在终端上安装"><a href="#在终端上安装" class="headerlink" title="在终端上安装"></a>在终端上安装</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可以在linux中执行以下命令来安装MongoDB 的 PHP 扩展驱动</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ sudo pecl install mongo</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;使用php的pecl安装命令必须保证网络连接可用以及root权限。</p>
<h4 id="安装手册"><a href="#安装手册" class="headerlink" title="安装手册"></a>安装手册</h4><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果想通过源码来编译扩展驱动。必须手动编译源码包，这样做的好是最新修正的bug包含在源码包中。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可以在Github上下载MongoDB PHP驱动包。访问github网站然后搜索”mongo php driver”<a href="https://github.com/mongodb/mongo-php-driver" target="_blank" rel="external">下载地址</a>，下载该源码包，然后执行以下命令：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">$ tar zxvf mongodb-mongodb-php-driver-&lt;commit_id&gt;.tar.gz</div><div class="line">$ <span class="built_in">cd</span> mongodb-mongodb-php-driver-&lt;commit_id&gt;</div><div class="line">$ phpize</div><div class="line">$ ./configure</div><div class="line">$ sudo make install</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果php是自己编译的，则安装方法如下(假设是编译在/usr/local/php目录中)：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">$ tar zxvf mongodb-mongodb-php-driver-&lt;commit_id&gt;.tar.gz</div><div class="line">$ <span class="built_in">cd</span> mongodb-mongodb-php-driver-&lt;commit_id&gt;</div><div class="line">$ /usr/<span class="built_in">local</span>/php/bin/phpize</div><div class="line">$ ./configure --with-php-config=/usr/<span class="built_in">local</span>/php/bin/php-config</div><div class="line">$ sudo make install</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;执行以上命令后，需要修改php.ini文件，在php.ini文件中添加mongo配置，配置如下：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">extension=mongo.so</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;注意：需要指明 extension_dir 配置项的路径。</p>
<h3 id="window上安装-MongoDB-PHP扩展"><a href="#window上安装-MongoDB-PHP扩展" class="headerlink" title="window上安装 MongoDB PHP扩展"></a>window上安装 MongoDB PHP扩展</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Github上已经提供了用于window平台的预编译php mongodb驱动二进制包 <a href="https://s3.amazonaws.com/drivers.mongodb.org/php/index.html" target="_blank" rel="external">下载地址</a>，你可以下载与你php对应的版本，但是你需要注意以下几点问题：</p>
<ul>
<li>VC6 是运行于 Apache 服务器</li>
<li>‘Thread safe’（线程安全）是运行在Apache上以模块的PHP上，如果你以CGI的模式运行PHP，请选择非线程安全模式（’ non-thread safe’）。</li>
<li>VC9是运行于 IIS 服务器上。</li>
<li>下载完你需要的二进制包后，解压压缩包，将’php_mongo.dll’文件添加到你的PHP扩展目录中（ext）。ext目录通常在PHP安装目录下的ext目录。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;打开php配置文件 php.ini 添加以下配置：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">extension=php_mongo.dll</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;重启服务器。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;通过浏览器访问phpinfo，如果安装成功，就会看到类型以下的信息：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/Linux%E4%B8%8A%E5%AE%89%E8%A3%85%20MongoDB%20PHP%E6%89%A9%E5%B1%95/01.png?raw=true" alt=""></figure></p>
<h3 id="MAC中安装MongoDB-PHP扩展驱动"><a href="#MAC中安装MongoDB-PHP扩展驱动" class="headerlink" title="MAC中安装MongoDB PHP扩展驱动"></a>MAC中安装MongoDB PHP扩展驱动</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可以使用’autoconf’安装MongoDB PHP扩展驱动。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可以使用’Xcode’安装MongoDB PHP扩展驱动。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果使用 XAMPP，可以使用以下命令安装MongoDB PHP扩展驱动：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sudo /Applications/XAMPP/xamppfiles/bin/pecl install mongo</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果以上命令在XMPP或者MAMP中不起作用，需要在Github上下载兼容的预编译包。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;然后添加 ‘extension=mongo.so’ 配置到你的php.ini文件中。</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/6. MongoDB 结合 PHP/">MongoDB 结合 PHP</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<h2 id="1-安装-PHP-的-MongoDB-扩展"><a href="#1-安装-PHP-的-MongoDB-扩展" class="headerlink" title="1.安装 PHP 的 MongoDB 扩展"></a>1.安装 PHP 的 MongoDB 扩展</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@primary ~]<span class="comment"># wget 'https://codeload.github.com/mongodb/mongo-php-driver/zip/master' -O /usr/local/src/mong_php.zip</span></div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">[root@primary ~]<span class="comment"># cd /usr/local/src</span></div><div class="line">[root@primary src]<span class="comment"># unzip mong_php.zip </span></div><div class="line">[root@primary src]<span class="comment"># cd mongo-php-driver-master/</span></div><div class="line">[root@primary mongo-php-driver-master]<span class="comment"># /usr/local/php/bin/phpize</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;出错无法解决，重新下载包</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">[root@primary ~]<span class="comment"># wget http://pecl.php.net/get/mongo-1.4.5.tgz</span></div><div class="line">[root@primary ~]<span class="comment"># tar xfv mongo-1.4.5.tgz </span></div><div class="line">[root@primary ~]<span class="comment"># cd mongo-1.4.5</span></div><div class="line">[root@primary mongo-1.4.5]<span class="comment"># /usr/local/php/bin/phpize </span></div><div class="line">[root@primary mongo-1.4.5]<span class="comment"># ./configure --with-php-config=/usr/local/php/bin/php-config</span></div><div class="line">[root@primary mongo-1.4.5]<span class="comment"># make &amp;&amp; make install</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;编辑 /usr/local/php/etc/php.ini </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@primary mongo-1.4.5]<span class="comment"># vim /usr/local/php/etc/php.ini</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;增加 extension = mongo.so</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">extension = mongo.so</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E7%BB%93%E5%90%88%20PHP/01.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;/usr/local/php/bin/php –m</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@primary mongo-1.4.5]<span class="comment"># /usr/local/php/bin/php -m</span></div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E7%BB%93%E5%90%88%20PHP/02.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;重启apache，重新加载php</p>
<h2 id="2-测试-MongoDB-扩展"><a href="#2-测试-MongoDB-扩展" class="headerlink" title="2.测试 MongoDB 扩展"></a>2.测试 MongoDB 扩展</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;编辑 /usr/local/apache2/htdocs/1.php </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@primary ~]<span class="comment"># vim /usr/local/apache2/htdocs/1.php</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;增加</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">&lt;?php</div><div class="line">// 连接到mongodb</div><div class="line"><span class="variable">$m</span> = new MongoClient();</div><div class="line"><span class="built_in">echo</span> <span class="string">"Connection to database successfully"</span>;</div><div class="line">// 选择一个数据库</div><div class="line"><span class="variable">$db</span> = <span class="variable">$m</span>-&gt;mydb;</div><div class="line"><span class="built_in">echo</span> <span class="string">"Database mydb selected"</span>;</div><div class="line">?&gt;</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E7%BB%93%E5%90%88%20PHP/03.png?raw=true" alt=""></figure></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">[root@primary ~]<span class="comment"># curl localhost/1.php</span></div><div class="line">Connection to database successfullyDatabase mydb selected</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;参考<a href="https://hcldirgit.github.io/2017/08/27/MongoDB/8.%20MongoDB%20PHP/" target="_blank" rel="external">MongoDB PHP</a></p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/5. MongoDB 备份和恢复/">MongoDB 备份和恢复</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<h2 id="1-MongoDB-备份"><a href="#1-MongoDB-备份" class="headerlink" title="1. MongoDB 备份"></a>1. MongoDB 备份</h2><h3 id="备份指定库"><a href="#备份指定库" class="headerlink" title="备份指定库"></a>备份指定库</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodump -h ip -d dbname -o dir</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;-h后面跟服务器ip，-d后面跟database名字，不加则备份所有库，-o后指定备份到哪里，它是一个目录</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/01.png?raw=true" alt="01"><figcaption class="figure__caption">01</figcaption></figure></p>
<h3 id="备份所有库"><a href="#备份所有库" class="headerlink" title="备份所有库"></a>备份所有库</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodump -h ip -o dir</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/02.png?raw=true" alt="02"><figcaption class="figure__caption">02</figcaption></figure></p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/03.png?raw=true" alt="03"><figcaption class="figure__caption">03</figcaption></figure></p>
<h3 id="备份指定集合"><a href="#备份指定集合" class="headerlink" title="备份指定集合"></a>备份指定集合</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodump -d mydb -c testc -o /tmp/testc</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;-c指定集合名字</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/04.png?raw=true" alt="04"><figcaption class="figure__caption">04</figcaption></figure></p>
<h3 id="导出集合为json文件"><a href="#导出集合为json文件" class="headerlink" title="导出集合为json文件"></a>导出集合为json文件</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongoexport -d mydb -c testc -o /tmp/testc.json</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;-o后面跟的是一个文件名字</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/05.png?raw=true" alt="05"><figcaption class="figure__caption">05</figcaption></figure></p>
<h2 id="2-MongoDB-恢复"><a href="#2-MongoDB-恢复" class="headerlink" title="2.MongoDB 恢复"></a>2.MongoDB 恢复</h2><p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/06.png?raw=true" alt="06"><figcaption class="figure__caption">06</figcaption></figure></p>
<h3 id="恢复所有库"><a href="#恢复所有库" class="headerlink" title="恢复所有库"></a>恢复所有库</h3><p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/07.png?raw=true" alt="07"><figcaption class="figure__caption">07</figcaption></figure></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongorestore --drop dir/</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;其中dir是备份所有库的目录名字，其中–drop可选，意思是当恢复之前先把之前的数据删除，不建议使用</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/08.png?raw=true" alt="08"><figcaption class="figure__caption">08</figcaption></figure></p>
<h3 id="恢复指定库"><a href="#恢复指定库" class="headerlink" title="恢复指定库"></a>恢复指定库</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongorestore -d mydb dir/</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;-d跟要恢复的库名字，dir就是该库备份时所在的目录</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/09.png?raw=true" alt="09"><figcaption class="figure__caption">09</figcaption></figure></p>
<h3 id="恢复集合"><a href="#恢复集合" class="headerlink" title="恢复集合"></a>恢复集合</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongorestore --drop -d mydb -c mycol /tmp/234/mydb/mycol.bson</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;-c后面跟要恢复的集合名字，dir是备份mydb库时生成文件所在路径，这里是一个bson文件的路径</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/10.png?raw=true" alt="10"><figcaption class="figure__caption">10</figcaption></figure></p>
<h3 id="导入集合"><a href="#导入集合" class="headerlink" title="导入集合"></a>导入集合</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongoimport -d mydb -c mycol --file /tmp/12345/mycol.json</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%A4%87%E4%BB%BD%E5%92%8C%E6%81%A2%E5%A4%8D/11.png?raw=true" alt="11"><figcaption class="figure__caption">11</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这里加 –drop 是因为之前恢复库和集合，所以加 –drop 强制覆盖。</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/4. MongoDB 副本集搭建/">MongoDB 副本集搭建</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<h2 id="MongoDB-副本集（repl-set-介绍"><a href="#MongoDB-副本集（repl-set-介绍" class="headerlink" title=".MongoDB 副本集（repl set)介绍"></a>.MongoDB 副本集（repl set)介绍</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;早期版本使用master-slave，一主一从和MySQL类似，但slave在此架构中为只读，当主库宕机后，从库不能自动切换为主</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;目前已经淘汰master-slave模式，改为副本集，这种模式下有一个主(primary)，和多个从(secondary)，只读。支持给它们设置权重，当主宕掉后，权重最高的从切换为主</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在此架构中还可以建立一个仲裁(arbiter)的角色，它只负责裁决，而不存储数据</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;再此架构中读写数据都是在主上，要想实现负载均衡的目的需要手动指定读库的目标server</p>
<h2 id="2-副本集架构图"><a href="#2-副本集架构图" class="headerlink" title="2.副本集架构图"></a>2.副本集架构图</h2><p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/01.png?raw=true" alt="01"><figcaption class="figure__caption">01</figcaption></figure></p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/02.png?raw=true" alt="02"><figcaption class="figure__caption">02</figcaption></figure></p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/03.png?raw=true" alt="03"><figcaption class="figure__caption">03</figcaption></figure></p>
<h2 id="3-MongoDB副本集搭建"><a href="#3-MongoDB副本集搭建" class="headerlink" title="3.MongoDB副本集搭建"></a>3.MongoDB副本集搭建</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;三台机器： 192.168.0.77（primary）   192.168.0.76（secondary)    192.168.0.75（secondary)</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;编辑三台机器的配置文件</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@primary ~]<span class="comment"># vim /etc/mongod.conf</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;增加：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">replication:</div><div class="line"><span class="comment">##oplog大小</span></div><div class="line">  oplogSizeMB: 20</div><div class="line"><span class="comment">##复制集名称</span></div><div class="line">  replSetName: yanyi</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/04.png?raw=true" alt="04"><figcaption class="figure__caption">04</figcaption></figure></p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/05.png?raw=true" alt="05"><figcaption class="figure__caption">05</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;分别重启三台机器</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;连接主，在主上运行命令mongo</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">&gt; use admin</div><div class="line">&gt; config=&#123;_id:<span class="string">"yanyi"</span>,members:[&#123;_id:0,host:<span class="string">"192.168.0.77:27017"</span>&#125;,&#123;_id:1,host:<span class="string">"192.168.0.76:27017"</span>&#125;,&#123;_id:2,host:<span class="string">"192.168.0.75:27017"</span>&#125;]&#125;</div><div class="line">&gt; rs.initiate(config)</div><div class="line">&gt; rs.add(<span class="string">"192.168.0.76"</span>)</div><div class="line">&gt; rs.add(<span class="string">"192.168.0.75"</span>)</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;rs.status() //查看状态</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果两个从上的状态为”stateStr” : “STARTUP”, 则需要进行如下操作</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">&gt; var config=&#123;_id:<span class="string">"yanyi"</span>,members:[&#123;_id:0,host:<span class="string">"192.168.0.77:27017"</span>&#125;,&#123;_id:1,host:<span class="string">"192.168.0.76:27017"</span>&#125;,&#123;_id:2,host:<span class="string">"192.168.0.75:27017"</span>&#125;]&#125;</div><div class="line">&gt;rs.reconfig(config)</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;此时再次查看rs.status()会发现从的状态变为SECONDARY</p>
<h2 id="4-MongoDB-副本集测试"><a href="#4-MongoDB-副本集测试" class="headerlink" title="4.MongoDB 副本集测试"></a>4.MongoDB 副本集测试</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;主上建库，建集合</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">yanyi:PRIMARY&gt; use mydb</div><div class="line">yanyi:PRIMARY&gt; db.acc.insert(&#123;AccountID:1,UserName:<span class="string">"123"</span>,password:<span class="string">"123456"</span>&#125;)</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">yanyi:PRIMARY&gt; show dbs</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/06.png?raw=true" alt="06"><figcaption class="figure__caption">06</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;从上查看</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/07.png?raw=true" alt="07"><figcaption class="figure__caption">07</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;若出现错误Error: listDatabases failed:{ “note” : “from execCommand”, “ok” : 0, “errmsg” : “not master” }，需要执行</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">yanyi:SECONDARY&gt; rs.slaveOk()</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/08.png?raw=true" alt="08"><figcaption class="figure__caption">08</figcaption></figure></p>
<h2 id="5-MongoDB副本集更改权重模拟主宕机"><a href="#5-MongoDB副本集更改权重模拟主宕机" class="headerlink" title="5.MongoDB副本集更改权重模拟主宕机"></a>5.MongoDB副本集更改权重模拟主宕机</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;默认三台机器权重都为1，如果任何一个权重设置为比其他的高，则该台机器马上切换为primary角色，所以我们预设三台机器的权重分别为：77:3,76:2,75:1</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在主上执行</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">yanyi:PRIMARY&gt; cfg = rs.conf()</div><div class="line">yanyi:PRIMARY&gt; cfg.members[0].priority = 3</div><div class="line">yanyi:PRIMARY&gt; cfg.members[1].priority = 2</div><div class="line">yanyi:PRIMARY&gt; cfg.members[2].priority = 1</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/09.png?raw=true" alt="09"><figcaption class="figure__caption">09</figcaption></figure></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">yanyi:PRIMARY&gt; rs.reconfig(cfg)</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%89%AF%E6%9C%AC%E9%9B%86%E6%90%AD%E5%BB%BA/10.png?raw=true" alt="10"><figcaption class="figure__caption">10</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这样的话，第二个节点将会成为候选主节点。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;主上执行 iptables -I INPUT -p tcp –dport 27017 -j DROP</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@primary ~]<span class="comment"># iptables -I INPUT -p tcp --dport 27017 -j DROP</span></div></pre></td></tr></table></figure>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/3. MongoDB 连接和用户管理/">MongoDB 连接和用户管理</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<h2 id="1-连接-MongoDB"><a href="#1-连接-MongoDB" class="headerlink" title="1.连接 MongoDB"></a>1.连接 MongoDB</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在本机可以直接运行命令mongo进入到mongodb shell中</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/01.png?raw=true" alt="01"><figcaption class="figure__caption">01</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果mongodb监听端口并不是默认的27017，则在连接的时候需要加–port 选项，例如</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/02.png?raw=true" alt="02"><figcaption class="figure__caption">02</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;连接远程mongodb，需要加–host，例如</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/03.png?raw=true" alt="03"><figcaption class="figure__caption">03</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果设置了验证，则在连接的时候需要带用户名和密码</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongo -uusername -ppasswd  <span class="comment">#这个和MySQL挺像</span></div></pre></td></tr></table></figure>
<h2 id="2-MongoDB-用户管理"><a href="#2-MongoDB-用户管理" class="headerlink" title="2. MongoDB 用户管理"></a>2. MongoDB 用户管理</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;首先mongodb用户是针对库来的，建立用户时要先进入到对应的库里</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">use <span class="built_in">test</span>  <span class="comment">#切换到test库下</span></div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/04.png?raw=true" alt="04"><figcaption class="figure__caption">04</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;创建用户</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&gt; db.createUser(&#123;user:<span class="string">"admin"</span>,<span class="built_in">pwd</span>:<span class="string">"123456"</span>,roles:[&#123;role:<span class="string">'dbOwner'</span>,db:<span class="string">'userdb'</span>&#125;]&#125;)</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/05.png?raw=true" alt="05"><figcaption class="figure__caption">05</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;use admin //切换到admin库</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/06.png?raw=true" alt="06"><figcaption class="figure__caption">06</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.system.users.find()  //列出所有用户，需要切换到admin库</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/07.png?raw=true" alt="07"><figcaption class="figure__caption">07</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;show users  //查看当前库下所有的用户</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/08.png?raw=true" alt="08"><figcaption class="figure__caption">08</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.dropUser(‘admin’) //删除用户</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/09.png?raw=true" alt="09"><figcaption class="figure__caption">09</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;关于用户角色，参考文档  <a href="">Mongodb 3.0 配置身份验证db.createUser()说明</a></p>
<h2 id="3-MongoDB-库管理"><a href="#3-MongoDB-库管理" class="headerlink" title="3.MongoDB 库管理"></a>3.MongoDB 库管理</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.version() // 查看版本</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/10.png?raw=true" alt="10"><figcaption class="figure__caption">10</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;use userdb // 如果库存在就切换，不存在就创建</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/11.png?raw=true" alt="11"><figcaption class="figure__caption">11</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;show dbs  // 查看库，此时userdb并没有出现，这是因为该库是空的，还没有任何集合，只需要创建一个集合就能看到了</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/12.png?raw=true" alt="12"><figcaption class="figure__caption">12</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.createCollection(‘clo1’) // 创建集合clo1，在当前库下面创建</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/13.png?raw=true" alt="13"><figcaption class="figure__caption">13</figcaption></figure></p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/14.png?raw=true" alt="14"><figcaption class="figure__caption">14</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.dropDatabase() // 删除当前库，要想删除某个库，必须切换到那个库下</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/15.png?raw=true" alt="15"><figcaption class="figure__caption">15</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.stats() // 查看当前库的信息</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/16.png?raw=true" alt="16"><figcaption class="figure__caption">16</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.serverStatus() // 查看mongodb服务器的状态</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/17.png?raw=true" alt="17"><figcaption class="figure__caption">17</figcaption></figure></p>
<h2 id="4-MongoDB-创建集合"><a href="#4-MongoDB-创建集合" class="headerlink" title="4.MongoDB 创建集合"></a>4.MongoDB 创建集合</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&gt; db.createCollection(<span class="string">"mycol"</span>, &#123; capped : <span class="literal">true</span>, autoIndexID : <span class="literal">true</span>, size : 6142800, max : 10000 &#125; )</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;语法：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">db.createCollection(name,options)</div></pre></td></tr></table></figure>
<ul>
<li><p>name就是集合的名字，options可选，用来配置集合的参数，参数如下</p>
</li>
<li><p>capped true/false （可选）如果为true，则启用封顶集合。封顶集合是固定大小的集合，当它达到其最大大小，会自动覆盖最早的条目。如果指定true，则也需要指定尺寸参数。</p>
</li>
<li><p>autoindexID  true/false （可选）如果为true，自动创建索引_id字段的默认值是false。</p>
</li>
<li><p>size （可选）指定最大大小字节封顶集合。如果封顶如果是 true，那么你还需要指定这个字段。单位B</p>
</li>
<li><p>max （可选）指定封顶集合允许在文件的最大数量。</p>
</li>
</ul>
<h2 id="5-MongoDB-数据管理"><a href="#5-MongoDB-数据管理" class="headerlink" title="5.MongoDB 数据管理"></a>5.MongoDB 数据管理</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;show collections //查看集合，或者使用show  tables</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/18.png?raw=true" alt="18"><figcaption class="figure__caption">18</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.Account.insert({AccountID:1,UserName:”123”,password:”123456”})  //如果集合不存在，直接插入数据，则mongodb会自动创建集合</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/19.png?raw=true" alt="19"><figcaption class="figure__caption">19</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.Account.update({AccountID:1},{“$set”:{“Age”:20}}) //更新</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/20.png?raw=true" alt="20"><figcaption class="figure__caption">20</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.Account.find()   //查看所有文档</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/21.png?raw=true" alt="21"><figcaption class="figure__caption">21</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.Account.find({AccountID:1})   //根据条件查询</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/22.png?raw=true" alt="22"><figcaption class="figure__caption">22</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.Account.remove({AccountID:1})  //根据条件删除</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/23.png?raw=true" alt="23"><figcaption class="figure__caption">23</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.Account.drop() //删除所有文档，即删除集合</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/24.png?raw=true" alt="24"><figcaption class="figure__caption">24</figcaption></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;use dbname  //先进入对应的库</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;db.printCollectionStats()  // 然后查看集合状态</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E8%BF%9E%E6%8E%A5%E5%92%8C%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86/25.png?raw=true" alt="25"><figcaption class="figure__caption">25</figcaption></figure></p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/2. MongoDB 安装/">MongoDB 安装</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<h2 id="1-搭建-yum-源"><a href="#1-搭建-yum-源" class="headerlink" title="1. 搭建 yum 源"></a>1. 搭建 yum 源</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果安装epel扩展源，可以安装mongodb2.4版本，但这次我们要安装3.0版本，官方提供的源只支持64位系统</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;编辑 /etc/yum.repos.d/mongodb-org-3.0.repo </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@mongodb ~]<span class="comment"># vim /etc/yum.repos.d/mongodb-org-3.0.repo</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;加入如下内容</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">[mongodb-org-3.0]</div><div class="line">name=MongoDB Repository</div><div class="line">baseurl=http://repo.mongodb.org/yum/redhat/<span class="variable">$releasever</span>/mongodb-org/3.0/x86_64/ </div><div class="line">gpgcheck=0</div><div class="line">enabled=1</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%AE%89%E8%A3%85/01.png?raw=true" alt=""></figure></p>
<h2 id="2-安装配置-MongoDB"><a href="#2-安装配置-MongoDB" class="headerlink" title="2. 安装配置 MongoDB"></a>2. 安装配置 MongoDB</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;安装很简单  yum install -y mongodb-org</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@mongodb ~]<span class="comment"># yum install -y mongodb-org</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;编辑配置文件 /etc/mongod.conf</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@mongodb ~]<span class="comment"># vim /etc/mongod.conf</span></div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">fork: <span class="literal">true</span></div><div class="line">pidFilePath: /var/run/mongodb/mongod.pid</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%AE%89%E8%A3%85/02.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;把这两行后面#开头的注释删掉,否则重启的时候会有问题</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%AE%89%E8%A3%85/03.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;要想绑定多个ip，在bind_ip 后写多个ip，中间用逗号分隔</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%AE%89%E8%A3%85/04.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;监听全部ip留空即可</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%AE%89%E8%A3%85/05.png?raw=true" alt=""></figure></p>
<h2 id="3-启动-MongoDB"><a href="#3-启动-MongoDB" class="headerlink" title="3. 启动 MongoDB"></a>3. 启动 MongoDB</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">[root@mongodb ~]<span class="comment"># /etc/init.d/mongod start</span></div><div class="line">Starting mongod: [确定]</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">[root@mongodb ~]<span class="comment"># echo never &gt; /sys/kernel/mm/transparent_hugepage/enabled</span></div><div class="line">[root@mongodb ~]<span class="comment"># echo never &gt; /sys/kernel/mm/transparent_hugepage/defrag</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;编辑 /etc/security/limits.conf </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">[root@mongodb ~]<span class="comment"># vim /etc/security/limits.conf</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;加入</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">mongod soft nofile 64000</div><div class="line">mongod hard nofile 64000</div><div class="line">mongod soft nproc 32000</div><div class="line">mongod hard nproc 32000</div></pre></td></tr></table></figure>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/MongoDB%20%E5%AE%89%E8%A3%85/06.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;启动：service mongod start</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">[root@mongodb ~]<span class="comment"># service mongod restart</span></div><div class="line">Stopping mongod: [确定]</div><div class="line">Starting mongod: [确定]</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;启动的过程会比较慢，这是它在写数据 /var/lib/mongo</p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/18. 连接字符串URI格式/">连接字符串URI格式</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;本文档描述了用于在官方MongoDB <a href="https://docs.mongodb.com/manual/applications/drivers/" target="_blank" rel="external">驱动程序</a>中定义应用程序和MongoDB实例之间的连接的URI格式。</p>
<h2 id="标准连接字符串格式"><a href="#标准连接字符串格式" class="headerlink" title="标准连接字符串格式"></a>标准连接字符串格式</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;本节介绍用于连接到MongoDB数据库服务器的MongoDB连接URI的标准格式。所有官方MongoDB驱动程序的格式是一样的。有关驱动程序列表和驱动程序文档的链接，请参阅<a href="https://docs.mongodb.com/manual/applications/drivers/" target="_blank" rel="external">MongoDB驱动程序和客户端库</a>。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下是标准的URI连接方案：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：// [username：password @] host1 [：port1] [，host2 [：port2]，... [，hostN [：portN]</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;此字符串的组件是：</p>
<table>
<thead>
<tr>
<th>mongodb://</th>
<th>用于标识这是标准连接格式的字符串的必需前缀。</th>
</tr>
</thead>
<tbody>
<tr>
<td>username:password@</td>
<td><a href="https://docs.mongodb.com/manual/reference/program/mongod/#bin.mongod" target="_blank" rel="external">可选的。如果指定，客户端将尝试在连接到mongod实例后使用这些凭据登录到特定数据库。</a></td>
</tr>
<tr>
<td>host1</td>
<td>需要。它标识要连接到的服务器地址。它标识主机名，IP地址或UNIX域套接字。对于副本集，请指定副本集配置mongod 中列出的实例的主机名。对于分片集群，请指定mongos实例的主机名 。</td>
</tr>
<tr>
<td>:port1</td>
<td>可选的。:27017如果未指定，则为默认值。</td>
</tr>
<tr>
<td>hostN</td>
<td>可选的。您可以根据需要指定任意数量的主机。您可以指定多个主机，例如，用于连接到副本集。对于副本集，请指定副本集配置mongod 中列出的实例的主机名。对于分片集群，请指定mongos实例的主机名 。</td>
</tr>
<tr>
<td>:portX</td>
<td>可选的。:27017如果未指定，则为默认值。/database可选的。要认证的数据库的名称，如果连接字符串包含的形式的认证凭证username:password@。如果/database未指定并且连接字符串包含凭据，则驱动程序将对admin数据库进行身份验证。</td>
</tr>
<tr>
<td>?options</td>
<td>连接特定选项。有关这些选项的完整描述，请参阅 连接字符串选项。如果连接字符串未指定数据库/，则必须/在最后一个hostN和开始于选项字符串的问号之间指定斜杠（即）。</td>
</tr>
</tbody>
</table>
<h3 id="例"><a href="#例" class="headerlink" title="例"></a>例</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;要<code>test</code>使用以下<a href="https://docs.mongodb.com/manual/reference/program/mongod/#bin.mongod" target="_blank" rel="external">mongod</a>主机描述与名为的副本集的连接：</p>
<ul>
<li>db1.example.net在港口27017和</li>
<li>db2.example.net端口2500。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;将使用类似于以下内容的连接字符串：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：//db1.example.net,db2.example.net：2500 /？replicaSet = <span class="built_in">test</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对于副本集，请指定副本集配置mongod 中列出的实例的主机名。</p>
<h3 id="例-1"><a href="#例-1" class="headerlink" title="例"></a>例</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;要使用以下mongos主机描述与分片群集的连接：</p>
<ul>
<li>r1.example.net在港口27017和</li>
<li>r2.example.net端口27017。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;将使用类似于以下内容的连接字符串：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：//r1.example.net：27017，r2.example.net：27017 /</div></pre></td></tr></table></figure>
<h2 id="连接字符串选项"><a href="#连接字符串选项" class="headerlink" title="连接字符串选项"></a>连接字符串选项</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;本节列出了在<a href="https://docs.mongodb.com/manual/reference/connection-string/#connections-standard-connection-string-format" target="_blank" rel="external">标准连接字符串格式中使用的所有连接选项</a> 。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;连接选项为以下形式的对：name=value。该 value永远是区分大小写的。使用＆号（即&amp;）字符分隔选项。在以下示例中，连接使用 replicaSet和connectTimeoutMS选项：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：//db1.example.net,db2.example.net：2500 /？replicaSet = <span class="built_in">test</span>＆connectTimeoutMS = 300000</div></pre></td></tr></table></figure>
<h2 id="连接字符串参数的分号分隔符"><a href="#连接字符串参数的分号分隔符" class="headerlink" title="连接字符串参数的分号分隔符"></a>连接字符串参数的分号分隔符</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;为了提供向后兼容性，驱动程序当前接受分号（即;）作为选项分隔符。</p>
<h2 id="副本集选项"><a href="#副本集选项" class="headerlink" title="副本集选项"></a>副本集选项</h2><table>
<thead>
<tr>
<th>连接选项</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>replicaSet</td>
<td>指定副本集的名称（如果 mongod是副本集的成员）。当连接到副本集时，重要的是给出至少两个mongod实例的种子列表。如果只提供单个mongod实例的连接点，并省略replicaSet，客户端将创建一个独立连接。</td>
</tr>
</tbody>
</table>
<h2 id="连接选项"><a href="#连接选项" class="headerlink" title="连接选项"></a>连接选项</h2><table>
<thead>
<tr>
<th>连接选项</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>ssl</td>
<td>true：使用TLS / SSL启动连接。false：启动不使用TLS / SSL的连接。默认值为false。注意:ssl所有驱动程序不支持该选项。请参阅您的驱动程序文档和配置mongod和mongos的TLS / SSL文档。</td>
</tr>
<tr>
<td>connectTimeoutMS</td>
<td><a href="https://docs.mongodb.com/manual/applications/drivers/" target="_blank" rel="external">超时前尝试连接的时间（以毫秒为单位）。默认是从不超时，虽然不同的驱动程序可能会有所不同。请参阅驱动程序 文档</a>。</td>
</tr>
<tr>
<td>socketTimeoutMS</td>
<td><a href="https://docs.mongodb.com/manual/applications/drivers/" target="_blank" rel="external">在尝试超时之前尝试在套接字上发送或接收的时间（以毫秒为单位）。默认是从不超时，虽然不同的驱动程序可能会有所不同。请参阅 驱动程序文档</a>。</td>
</tr>
</tbody>
</table>
<h2 id="连接池选项"><a href="#连接池选项" class="headerlink" title="连接池选项"></a>连接池选项</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;大多数驱动程序实现某种连接池处理。某些驱动程序不支持连接池。有关连接池实现的更多信息，请参见<a href="https://docs.mongodb.com/manual/applications/drivers/" target="_blank" rel="external">驱动程序</a>文档。这些选项允许应用程序在连接到MongoDB部署时配置连接池。</p>
<table>
<thead>
<tr>
<th>连接选项</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>maxPoolSize</td>
<td>连接池中的最大连接数。默认值为100。</td>
</tr>
<tr>
<td>minPoolSize</td>
<td>连接池中的最小连接数。默认值为0。注意,minPoolSize所有驱动程序不支持该选项。有关您的驱动程序的信息，请参阅驱动程序文档。</td>
</tr>
<tr>
<td>maxIdleTimeMS</td>
<td>在删除和关闭之前，连接在池中保持空闲的最大毫秒数。此选项不受所有驱动程序支持。</td>
</tr>
<tr>
<td>waitQueueMultipl</td>
<td>e驱动程序将maxPoolSize 值乘以的数字，以提供允许等待连接从池中可用的最大线程数。有关默认值，请参阅MongoDB驱动程序和客户端库 文档。</td>
</tr>
<tr>
<td>waitQueueTimeoutMS</td>
<td>线程可以等待连接变为可用的最大时间（以毫秒为单位）。有关默认值，请参阅MongoDB驱动程序和客户端库文档。</td>
</tr>
</tbody>
</table>
<h2 id="写关注选项"><a href="#写关注选项" class="headerlink" title="写关注选项"></a>写关注选项</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<a href="https://docs.mongodb.com/manual/reference/write-concern/#write-concern" target="_blank" rel="external">写关注</a>描述了<a href="https://docs.mongodb.com/manual/reference/program/mongod/#bin.mongod" target="_blank" rel="external">mongod</a>和驱动程序向应用程序提供的关于写操作的成功和持久性的保证类型。有关写入关注和写入操作的完整说明，请参阅 <a href="https://docs.mongodb.com/manual/reference/write-concern/" target="_blank" rel="external">写入注意事项</a>。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>注意</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>可以在连接字符串中指定写入注意事项，也可以将方法调用的参数指定为insert或update。如果在两个地方都指定了写入关注，方法参数将覆盖connection-string设置。</strong></p>
<table>
<thead>
<tr>
<th>连接选项</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>w</td>
<td>对应写入关注w选项。该w选项请求确认写操作已传播到指定数量的mongod实例或mongod指定标签的实例。您可以指定a number，字符串majority或a 。tag set。有关详细信息，请参见w选项。</td>
</tr>
<tr>
<td>wtimeoutMS</td>
<td>对应于写入关键字wtimeout。wtimeoutMS指定写入关注的时间限制（以毫秒为单位）。当wtimeoutMS是0，写操作永远不会超时。有关更多信息，请参阅wtimeout。</td>
</tr>
<tr>
<td>journal</td>
<td>对应于写入关注j选项选项。该 journal选项请求MongoDB确认写操作已写入 日志。有关详细信息，请参阅j选项。如果设置journal为true，并指定w小于1 的 值，则journal优先。在2.6版更改：如果设置journal为true，并且 mongod没有启用日记功能，如storage.journal.enabled，然后MongoDB将会报错。在以前的版本中，MongoDB将提供基本接收确认（即w:1），忽略journal，并jnote在其返回文档中包含一个字段。</td>
</tr>
</tbody>
</table>
<h2 id="readConcern选项"><a href="#readConcern选项" class="headerlink" title="readConcern选项"></a>readConcern选项</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;3.2版本中的新功能：对于WiredTiger存储引擎，MongoDB 3.2为副本集和副本集分片引入了readConcern选项。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<a href="https://docs.mongodb.com/manual/reference/read-concern/" target="_blank" rel="external">读取关注</a>允许客户端为其从副本集的读取选择隔离级别。</p>
<table>
<thead>
<tr>
<th>连接选项</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>readConcernLevel</td>
<td>隔离的水平。接受”local”或 “majority”。有关详细信息，请参阅阅读关注。</td>
</tr>
</tbody>
</table>
<h2 id="读取首选项"><a href="#读取首选项" class="headerlink" title="读取首选项"></a>读取首选项</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<a href="https://docs.mongodb.com/manual/core/read-preference/" target="_blank" rel="external">读取首选项</a>描述了关于<a href="https://docs.mongodb.com/manual/reference/glossary/#term-replica-set" target="_blank" rel="external">副本集</a>的读取操作的行为。这些参数允许您在连接字符串中基于每个连接指定读取首选项：</p>
<table>
<thead>
<tr>
<th>连接选项</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>readPreference</td>
<td>指定此连接的副本集读取首选项。读取首选项值如下：primary、primaryPreferred、secondary、secondaryPreferred、nearest。有关每个值的说明，请参阅 阅读首选项模式。默认值为primary，将所有读取操作发送到副本集的主数据库。</td>
</tr>
<tr>
<td>maxStalenessSeconds</td>
<td>新版本3.4。指定辅助节点在客户端停止将其用于读取操作之前的陈旧时间（秒）。有关详细信息，请参阅：maxStalenessSeconds。默认情况下，没有最大过期，客户端在选择读取操作的位置时不会考虑次要的延迟。最小值maxStalenessSeconds为90秒。指定0和90秒之间的值将产生错误。MongoDB驱动程序将maxStalenessSeconds值-1视为“no max staleness”，与 maxStalenessSeconds省略时相同。重要。要使用maxStalenessSeconds，部署中的所有MongoDB实例必须使用MongoDB 3.4或更高版本。如果任何实例在早期版本的MongoDB上，驱动程序或mongos将引发错误。以下指定secondary读取首选项模式的maxStalenessSeconds值为120秒：mongodb：//host.example.com/？readPreference = secondary＆maxStalenessSeconds = 120</td>
</tr>
<tr>
<td>readPreferenceTags</td>
<td>指定标记集，以逗号分隔的冒号分隔的键值对列表。例如：dc：ny，rack：1 要指定标记集的列表，请使用多个 readPreferenceTags。以下指定两个标记集和一个空标记集：readPreferenceTags = dc：ny，rack：1＆readPreferenceTags = dc：ny＆readPreferenceTags = 使用多个时订单重要readPreferenceTags。</td>
</tr>
</tbody>
</table>
<h2 id="验证选项"><a href="#验证选项" class="headerlink" title="验证选项"></a>验证选项</h2><p>连接选项|描述<br>authSource|指定与用户凭据关联的数据库名称。authSource默认为在连接字符串中指定的数据库。对于将凭证存储委托给其他服务的身份验证机制，该authSource值应 $external与PLAIN（LDAP）和GSSAPI （Kerberos）身份验证机制相同。authSource如果连接字符串指定没有用户名，MongoDB将忽略值。<br>authMechanism|改变在2.6版本：为新增支持PLAIN和MONGODB-X509 认证机制。在版本3.0中更改：添加对SCRAM-SHA-1身份验证机制的支持。指定MongoDB将用来认证连接的认证机制。可能的值包括：SCRAM-SHA-1、MONGODB-CR、MONGODB-X509、GSSAPI（Kerberos）、PLAIN（LDAP SASL）、只有MongoDB Enterprise mongod和mongos 实例提供GSSAPI（Kerberos）和PLAIN（LDAP）机制。要使用MONGODB-X509，您必须启用TLS / SSL。有关MongoDB中的身份验证系统的详细信息，请参阅身份验证。还要考虑 使用x.509证书来认证客户端以获取有关x509 身份验证的更多信息。<br>gssapiServiceName|连接到Kerberos MongoDB实例时设置Kerberos服务名称。此值必须与在MongoDB实例上设置的服务名称匹配。gssapiServiceName默认mongodb为所有客户端和MongoDB实例。如果更改saslServiceNameMongoDB实例上的设置，则需要设置gssapiServiceName为相同的值。</p>
<h2 id="服务器选择和发现选项"><a href="#服务器选择和发现选项" class="headerlink" title="服务器选择和发现选项"></a>服务器选择和发现选项</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;MongoDB提供以下选项来配置MongoDB驱动程序和实例如何mongos选择要将读取或写入操作定向到的服务器。</p>
<table>
<thead>
<tr>
<th>连接选项</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>localThresholdMS</td>
<td>用于在多个合适的MongoDB实例之间进行选择的延迟窗口的大小（以毫秒为单位）。默认值：15毫秒。所有驱动程序使用localThresholdMS。localThreshold指定延迟窗口大小时使用 别名mongos。</td>
</tr>
<tr>
<td>serverSelectionTimeoutMS</td>
<td>指定在抛出异常之前阻止服务器选择的时间长度（以毫秒为单位）。默认值：30,000毫秒。</td>
</tr>
<tr>
<td>serverSelectionTryOnce</td>
<td>仅限单线程驱动程序。When true，指示驱动程序在服务器选择失败之后一次扫描MongoDB部署，然后选择服务器或引发错误。当时false，驱动程序阻止并搜索一个服务器，直到该serverSelectionTimeoutMS值。 默认值：true。多线程驱动程序和mongos不支持 serverSelectionTryOnce。</td>
</tr>
<tr>
<td>heartbeatFrequencyMS</td>
<td>heartbeatFrequencyMS控制驱动程序检查MongoDB部署的状态。指定检查之间的间隔（以毫秒为单位），从上一个检查结束开始计算，直到下一个检查结束。默认值：单线程驱动程序：60秒。多线程驱动程序：10秒。mongos 不支持更改心跳检查的频率。</td>
</tr>
</tbody>
</table>
<h2 id="其他配置"><a href="#其他配置" class="headerlink" title="其他配置"></a>其他配置</h2><table>
<thead>
<tr>
<th>连接选项</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>uuidRepresentation</td>
<td>可能的值为：standard标准二进制表示。csharpLegacy。C＃驱动程序的默认表示。javaLegacy。Java驱动程序的默认表示。pythonLegacy。Python驱动程序的默认表示。有关默认值，请参阅驱动程序的驱动程序 文档。注意：并不是所有的驱动程序都支持该uuidRepresentation 选项。有关您的驱动程序的信息，请参阅驱动程序文档。</td>
</tr>
</tbody>
</table>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;示例</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下提供了公共连接目标的示例URI字符串。</p>
<h3 id="数据库服务器在本地运行"><a href="#数据库服务器在本地运行" class="headerlink" title="数据库服务器在本地运行"></a>数据库服务器在本地运行</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下连接到在默认端口上本地运行的数据库服务器：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：// localhost</div></pre></td></tr></table></figure>
<h3 id="admin数据库"><a href="#admin数据库" class="headerlink" title="admin数据库"></a>admin数据库</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下以具有密码的admin用户身份连接并登录到数据库 ：sysopmoon</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：// sysop：moon @ localhost</div></pre></td></tr></table></figure>
<h3 id="records数据库"><a href="#records数据库" class="headerlink" title="records数据库"></a>records数据库</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下以具有密码的records用户身份连接并登录到数据库 ：sysopmoon</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：// sysop：moon @ localhost / records</div></pre></td></tr></table></figure>
<h3 id="Unix域套接字"><a href="#Unix域套接字" class="headerlink" title="Unix域套接字"></a>Unix域套接字</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;连接到UNIX域套接字时，请使用URL编码的连接字符串。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下连接到具有文件路径的UNIX域套接字 /tmp/mongodb-27017.sock：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：//%2Ftmp%2Fmongodb-27017.sock</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>注意</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<code>并非所有驱动程序都支持UNIX域套接字。有关您的驱动程序的信息，请参阅驱动程序 文档。</code></p>
<h3 id="不同机器上的成员的副本集"><a href="#不同机器上的成员的副本集" class="headerlink" title="不同机器上的成员的副本集"></a>不同机器上的成员的副本集</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下连接到具有两个成员的副本集，一个打开 db1.example.net，另一个打开db2.example.net：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>注意</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<code>对于副本集，请指定副本集配置mongod 中列出的实例的主机名。</code></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：//db1.example.net,db2.example.com/？replicaSet = <span class="built_in">test</span></div></pre></td></tr></table></figure>
<h3 id="复制集与成员上localhost"><a href="#复制集与成员上localhost" class="headerlink" title="复制集与成员上localhost"></a>复制集与成员上localhost</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;下面连接到具有三个成员上运行副本集localhost上的端口27017，27018以及27019：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>注意</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对于副本集，请指定副本集配置mongod 中列出的实例的主机名。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：// localhost，localhost：27018，localhost：27019 /？replicaSet = <span class="built_in">test</span></div></pre></td></tr></table></figure>
<h3 id="读分配的副本集"><a href="#读分配的副本集" class="headerlink" title="读分配的副本集"></a>读分配的副本集</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下连接到具有三个成员的副本集，并将读取分发给辅助节点：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<em>*注意</em></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;对于副本集，请指定副本集配置mongod 中列出的实例的主机名。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：//example1.com,example2.com,example3.com/？replicaSet = <span class="built_in">test</span>＆readPreference = secondary</div></pre></td></tr></table></figure>
<h3 id="具有高级写入关注的副本集"><a href="#具有高级写入关注的副本集" class="headerlink" title="具有高级写入关注的副本集"></a>具有高级写入关注的副本集</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下连接到具有写入关注的副本集，配置为等待复制在至少两个成员上成功，具有两秒超时。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>注意</strong></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<code>对于副本集，请指定副本集配置mongod 中列出的实例的主机名。</code></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：//example1.com,example2.com,example3.com/？replicaSet = <span class="built_in">test</span>＆w = 2＆wtimeoutMS = 2000</div></pre></td></tr></table></figure>
<h3 id="集群"><a href="#集群" class="headerlink" title="集群"></a>集群</h3><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;以下连接到具有三个mongos实例的分片集群：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">mongodb：//router1.example.com：27017，router2.example2.com：27017，router3.example3.com：27017 /</div></pre></td></tr></table></figure>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/16. 搭建高可用mongodb集群—— 深入副本集内部机制/">搭建高可用mongodb集群—— 深入副本集内部机制</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在<a href="https://hcldirgit.github.io/2017/08/27/MongoDB/15.%20%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%89%AF%E6%9C%AC%E9%9B%86/" target="_blank" rel="external">搭建高可用mongodb集群—— 副本集</a>介绍了副本集的配置，这篇文章深入研究一下副本集的内部机制。还是带着副本集的问题来看吧！</p>
<ul>
<li>副本集故障转移，主节点是如何选举的？能否手动干涉下架某一台主节点。</li>
<li>官方说副本集数量最好是奇数，为什么？</li>
<li>mongodb副本集是如何同步的？如果同步不及时会出现什么情况？会不会出现不一致性？</li>
<li>mongodb的故障转移会不会无故自动发生？什么条件会触发？频繁触发可能会带来系统负载加重？</li>
</ul>
<h2 id="Bully算法"><a href="#Bully算法" class="headerlink" title="Bully算法"></a>Bully算法</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mongodb副本集故障转移功能得益于它的选举机制。选举机制采用了Bully算法，可以很方便从分布式节点中选出主节点。一个分布式集群架构中一般都有一个所谓的主节点，可以有很多用途，比如缓存机器节点元数据，作为集群的访问入口等等。主节点有就有吧，我们干嘛要什么Bully算法？要明白这个我们先看看这两种架构：</p>
<ol>
<li>指定主节点的架构，这种架构一般都会申明一个节点为主节点，其他节点都是从节点，如我们常用的mysql就是这样。但是这样架构我们在第一节说了整个集群如果主节点挂掉了就得手工操作，上架一个新的主节点或者从从节点恢复数据，不太灵活。</li>
</ol>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E6%B7%B1%E5%85%A5%E5%89%AF%E6%9C%AC%E9%9B%86%E5%86%85%E9%83%A8%E6%9C%BA%E5%88%B6/01.png?raw=true" alt=""></figure></p>
<ol>
<li>不指定主节点，集群中的任意节点都可以成为主节点。mongodb也就是采用这种架构，一但主节点挂了其他从节点自动接替变成主节点。如下图：</li>
</ol>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E6%B7%B1%E5%85%A5%E5%89%AF%E6%9C%AC%E9%9B%86%E5%86%85%E9%83%A8%E6%9C%BA%E5%88%B6/02.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;好了，问题就在这个地方，既然所有节点都是一样，一但主节点挂了，怎么选择出来下一个节点是谁来做为主节点呢？这就是Bully算法解决的问题。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;那什么是Bully算法，<strong>Bully算法</strong>是一种协调者（主节点）竞选算法，主要思想是集群的每个成员都可以声明它是主节点并通知其他节点。别的节点可以选择接受这个声称或是拒绝并进入主节点竞争。被其他所有节点接受的节点才能成为主节点。节点按照一些属性来判断谁应该胜出。这个属性可以是一个静态ID，也可以是更新的度量像最近一次事务ID（最新的节点会胜出）。详情请参考<a href="http://blog.nosqlfan.com/html/4139.html" target="_blank" rel="external">NoSQL数据库分布式算法的协调者竞选</a>还有<a href="https://en.wikipedia.org/wiki/Bully_algorithm" target="_blank" rel="external">维基百科的解释</a> 。</p>
<h2 id="选举"><a href="#选举" class="headerlink" title="选举"></a>选举</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;那mongodb是怎进行选举的呢？官方这么描述:</p>
<blockquote>
<p>We use a consensus protocol to pick a primary. Exact details will be spared here but that basic process is:</p>
<ol>
<li>get maxLocalOpOrdinal from each server.</li>
<li>if a majority of servers are not up (from this server’s POV), remain in Secondary mode and stop.</li>
<li>if the last op time seems very old, stop and await human intervention.</li>
<li>else, using a consensus protocol, pick the server with the highest maxLocalOpOrdinal as the Primary.</li>
</ol>
</blockquote>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;大致翻译过来为使用一致协议选择主节点。基本步骤为：</p>
<ol>
<li><p>得到每个服务器节点的最后操作时间戳。每个mongodb都有oplog机制会记录本机的操作，方便和主服务器进行对比数据是否同步还可以用于错误恢复。</p>
</li>
<li><p>如果集群中大部分服务器down机了，保留活着的节点都为 secondary状态并停止，不选举了。</p>
</li>
<li><p>如果集群中选举出来的主节点或者所有从节点最后一次同步时间看起来很旧了，停止选举等待人来操作。</p>
</li>
<li><p>如果上面都没有问题就选择最后操作时间戳最新（保证数据是最新的）的服务器节点作为主节点。</p>
</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这里提到了一个一致协议（其实就是bully算法），这个和数据库的一致性协议还是有些区别，一致协议主要强调的是通过一些机制保证大家达成共识；而一致性协议强调的是操作的顺序一致性，比如同时读写一个数据会不会出现脏数据。一致协议在分布式里有一个经典的算法叫“Paxos算法”，后续再介绍。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;上面有个问题，就是所有从节点的最后操作时间都是一样怎么办？就是谁先成为主节点的时间最快就选谁。</p>
<h2 id="选举触发条件"><a href="#选举触发条件" class="headerlink" title="选举触发条件"></a>选举触发条件</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;选举不是什么时刻都会被触发的，有以下情况可以触发。</p>
<ol>
<li><p>初始化一个副本集时。</p>
</li>
<li><p>副本集和主节点断开连接，可能是网络问题。</p>
</li>
<li><p>主节点挂掉。</p>
</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;选举还有个前提条件，参与选举的节点数量必须大于副本集总节点数量的一半，如果已经小于一半了所有节点保持只读状态。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;日志将会出现：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">can<span class="string">'t see a majority of the set, relinquishing primary</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;主节点挂掉能否人为干预？答案是肯定的。</p>
<ol>
<li>可以通过replSetStepDown命令下架主节点。这个命令可以登录主节点使用</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">db.adminCommand(&#123;replSetStepDown : 1&#125;)</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果杀不掉可以使用强制开关</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">db.adminCommand(&#123;replSetStepDown : 1, force : <span class="literal">true</span>&#125;)</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;或者使用 rs.stepDown(120)也可以达到同样的效果，中间的数字指不能在停止服务这段时间成为主节点，单位为秒。</p>
<ol>
<li>设置一个从节点有比主节点有更高的优先级。</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;先查看当前集群中优先级，通过rs.conf()命令，默认优先级为1是不显示的，这里标示出来。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">rs.conf();</div><div class="line">&#123;</div><div class="line">        <span class="string">"_id"</span> : <span class="string">"rs0"</span>,</div><div class="line">        <span class="string">"version"</span> : 9,</div><div class="line">        <span class="string">"members"</span> : [</div><div class="line">                &#123;</div><div class="line">                        <span class="string">"_id"</span> : 0,</div><div class="line">                        <span class="string">"host"</span> : <span class="string">"192.168.1.136:27017"</span> &#125;,</div><div class="line">                &#123;</div><div class="line">                        <span class="string">"_id"</span> : 1,</div><div class="line">                        <span class="string">"host"</span> : <span class="string">"192.168.1.137:27017"</span> &#125;,</div><div class="line">                &#123;</div><div class="line">                        <span class="string">"_id"</span> : 2,</div><div class="line">                        <span class="string">"host"</span> : <span class="string">"192.168.1.138:27017"</span> &#125;</div><div class="line">        ]</div><div class="line">        &#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;我们来设置，让id为1的主机可以优先成为主节点。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">cfg = rs.conf()</div><div class="line">cfg.members[0].priority = 1</div><div class="line">cfg.members[1].priority = 2</div><div class="line">cfg.members[2].priority = 1</div><div class="line">rs.reconfig(cfg)</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;然后再执行rs.conf()命令查看优先级已经设置成功，主节点选举也会触发。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line">        <span class="string">"_id"</span> : <span class="string">"rs0"</span>,</div><div class="line">        <span class="string">"version"</span> : 9,</div><div class="line">        <span class="string">"members"</span> : [</div><div class="line">                &#123;</div><div class="line">                        <span class="string">"_id"</span> : 0,</div><div class="line">                        <span class="string">"host"</span> : <span class="string">"192.168.1.136:27017"</span> &#125;,</div><div class="line">                &#123;</div><div class="line">                        <span class="string">"_id"</span> : 1,</div><div class="line">                        <span class="string">"host"</span> : <span class="string">"192.168.1.137:27017"</span>,</div><div class="line">                        <span class="string">"priority"</span> : 2</div><div class="line">                 &#125;,</div><div class="line">                 &#123;</div><div class="line">                        <span class="string">"_id"</span> : 2,</div><div class="line">                        <span class="string">"host"</span> : <span class="string">"192.168.1.138:27017"</span> &#125;</div><div class="line">                 ]</div><div class="line">                 &#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如果不想让一个从节点成为主节点可以怎么操作？</p>
<ul>
<li>使用rs.freeze(120)冻结指定的秒数不能选举成为主节点。</li>
<li>按照上一篇设置节点为Non-Voting类型。</li>
</ul>
<ol>
<li>当主节点不能和大部分从节点通讯。把主机节点网线拔掉，嘿嘿：）</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;优先级还可以这么用，如果我们不想设置什么hidden节点，就用secondary类型作为备份节点也不想让他成为主节点怎么办？看下图，共三个节点分布在两个数据中心，数据中心2的节点设置优先级为0不能成为主节点，但是可以参与选举、数据复制。架构还是很灵活吧！</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E6%B7%B1%E5%85%A5%E5%89%AF%E6%9C%AC%E9%9B%86%E5%86%85%E9%83%A8%E6%9C%BA%E5%88%B6/03.png?raw=true" alt=""></figure></p>
<h2 id="奇数"><a href="#奇数" class="headerlink" title="奇数"></a>奇数</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;官方推荐副本集的成员数量为奇数，最多12个副本集节点，最多7个节点参与选举。最多12个副本集节点是因为没必要一份数据复制那么多份，备份太多反而增加了网络负载和拖慢了集群性能；而最多7个节点参与选举是因为内部选举机制节点数量太多就会导致1分钟内还选不出主节点，凡事只要适当就好。这个“12”、“7”数字还好，通过他们官方经过性能测试定义出来可以理解。具体还有哪些限制参考官方文档<a href="https://docs.mongodb.com/manual/reference/limits/" target="_blank" rel="external">《 MongoDB Limits and Thresholds 》</a>但是这里一直没搞懂整个集群为什么要奇数，通过测试集群的数量为偶数也是可以运行的，参考这个文章 <a href="https://hcldirgit.github.io/2017/08/27/MongoDB/13.%20MongoDB%E2%80%9C%E5%85%B3%E4%BA%8EReplSet%E6%88%90%E5%91%98%E5%BF%85%E9%A1%BB%E4%B8%BA%E5%A5%87%E6%95%B0%E2%80%9D%E7%9A%84%E8%AF%B4%E6%B3%95%EF%BC%8C%E5%85%B6%E5%AE%9E%E6%88%90%E5%91%98%E8%8A%82%E7%82%B9%E6%95%B0%E7%9B%AE%E5%8F%AF%E4%BB%A5%E4%B8%BA%E5%81%B6%E6%95%B0%E7%9A%84/" target="_blank" rel="external">MongoDB “关于ReplSet成员必须为奇数”的说法，其实成员节点数目可以为偶数的</a>。后来突然看了一篇stackoverflow的文章终于顿悟了，mongodb本身设计的就是一个可以跨IDC的分布式数据库，所以我们应该把它放到大的环境来看。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;假设四个节点被分成两个IDC，每个IDC各两台机器，如下图。但这样就出现了个问题，如果两个IDC网络断掉，这在广域网上很容易出现的问题，在上面选举中提到只要主节点和集群中大部分节点断开链接就会开始一轮新的选举操作，不过mongodb副本集两边都只有两个节点，但是选举要求参与的节点数量必须大于一半，这样所有集群节点都没办法参与选举，只会处于只读状态。但是如果是奇数节点就不会出现这个问题，假设3个节点，只要有2个节点活着就可以选举，5个中的3个，7个中的4个。。。</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E6%B7%B1%E5%85%A5%E5%89%AF%E6%9C%AC%E9%9B%86%E5%86%85%E9%83%A8%E6%9C%BA%E5%88%B6/04.png?raw=true" alt=""></figure></p>
<h2 id="心跳"><a href="#心跳" class="headerlink" title="心跳"></a>心跳</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;综上所述，整个集群需要保持一定的通信才能知道哪些节点活着哪些节点挂掉。mongodb节点会向副本集中的其他节点每两秒就会发送一次pings包，如果其他节点在10秒钟之内没有返回就标示为不能访问。每个节点内部都会维护一个状态映射表，表明当前每个节点是什么角色、日志时间戳等关键信息。如果是主节点，除了维护映射表外还需要检查自己能否和集群中内大部分节点通讯，如果不能则把自己降级为secondary只读节点。</p>
<h2 id="同步"><a href="#同步" class="headerlink" title="同步"></a>同步</h2><p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;副本集同步分为初始化同步和keep复制。初始化同步指全量从主节点同步数据，如果主节点数据量比较大同步时间会比较长。而keep复制指初始化同步过后，节点之间的实时同步一般是增量同步。初始化同步不只是在第一次才会被处罚，有以下两种情况会触发：</p>
<ol>
<li><p>secondary第一次加入，这个是肯定的。</p>
</li>
<li><p>secondary落后的数据量超过了oplog的大小，这样也会被全量复制。</p>
</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;那什么是oplog的大小？前面说过oplog保存了数据的操作记录，secondary复制oplog并把里面的操作在secondary执行一遍。但是oplog也是mongodb的一个集合，保存在 local.oplog.rs里，但是这个oplog是一个capped collection也就是固定大小的集合，新 数据加入超过集合的大小会覆盖。所以这里需要注意，跨IDC的复制要设置合适的oplogSize，避免在生产环境经常产生全量复制。oplogSize 可以通过–oplogSize设置大小，对于linux 和windows 64位，oplog size默认为剩余磁盘空间的5%。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;同步也并非只能从主节点同步，假设集群中3个节点，节点1是主节点在IDC1，节点2、节点3在IDC2，初始化节点2、节点3会从节点1同步数据。后面节点2、节点3会使用就近原则从当前IDC的副本集中进行复制，只要有一个节点从IDC1的节点1复制数据。<br>设置同步还要注意以下几点：</p>
<ol>
<li><p>secondary不会从delayed和hidden成员上复制数据。</p>
</li>
<li><p>只要是需要同步，两个成员的buildindexes必须要相同无论是否是true和false。buildindexes主要用来设置是否这个节点的数据用于查询，默认为true。</p>
</li>
<li><p>如果同步操作30秒都没有反应，则会重新选择一个节点进行同步。</p>
</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;到此，本章前面提到的问题全部解决了，不得不说mongodb的设计还真是强大！</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;后续继续解决上一节这几个问题：</p>
<ul>
<li>主节点挂了能否自动切换连接？目前需要手工切换。</li>
<li>主节点的读写压力过大如何解决？</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;还有这两个问题后续解决：</p>
<ul>
<li>从节点每个上面的数据都是对数据库全量拷贝，从节点压力会不会过大？</li>
<li>数据压力大到机器支撑不了的时候能否做到自动扩展？</li>
</ul>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/17. 搭建高可用mongodb集群—— 分片/">搭建高可用mongodb集群—— 分片</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;按照<a href="https://hcldirgit.github.io/2017/08/28/MongoDB/16.%20%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E6%B7%B1%E5%85%A5%E5%89%AF%E6%9C%AC%E9%9B%86%E5%86%85%E9%83%A8%E6%9C%BA%E5%88%B6/" target="_blank" rel="external">搭建高可用mongodb集群—— 深入副本集内部机制</a>搭建后还有两个问题没有解决：</p>
<ul>
<li>从节点每个上面的数据都是对数据库全量拷贝，从节点压力会不会过大？</li>
<li>数据压力大到机器支撑不了的时候能否做到自动扩展？</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在系统早期，数据量还小的时候不会引起太大的问题，但是随着数据量持续增多，后续迟早会出现一台机器硬件瓶颈问题的。而mongodb主打的就是海量数据架构，他不能解决海量数据怎么行！不行！“分片”就用这个来解决这个问题。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;传统数据库怎么做海量数据读写？其实一句话概括：分而治之。上图看看就清楚了，如下 taobao岳旭强在infoq中提到的 架构图：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%88%86%E7%89%87/01.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;上图中有个TDDL，是taobao的一个数据访问层组件，他主要的作用是SQL解析、路由处理。根据应用的请求的功能解析当前访问的sql判断是在哪个业务数据库、哪个表访问查询并返回数据结果。具体如图：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%88%86%E7%89%87/02.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;说了这么多传统数据库的架构，那Nosql怎么去做到了这些呢？mysql要做到自动扩展需要加一个数据访问层用程序去扩展，数据库的增加、删除、备份还需要程序去控制。一但数据库的节点一多，要维护起来也是非常头疼的。不过mongodb所有的这一切通过他自己的内部机制就可以搞定！顿时石化了，这么牛X！还是上图看看mongodb通过哪些机制实现路由、分片：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%88%86%E7%89%87/03.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;从图中可以看到有四个组件：mongos、config server、shard、replica set。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>mongos</strong>，数据库集群请求的入口，所有的请求都通过mongos进行协调，不需要在应用程序添加一个路由选择器，mongos自己就是一个请求分发中心，它负责把对应的数据请求请求转发到对应的shard服务器上。在生产环境通常有多mongos作为请求的入口，防止其中一个挂掉所有的mongodb请求都没有办法操作。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>config server</strong>，顾名思义为配置服务器，存储所有数据库元信息（路由、分片）的配置。mongos本身没有物理存储分片服务器和数据路由信息，只是缓存在内存里，配置服务器则实际存储这些数据。mongos第一次启动或者关掉重启就会从 config server 加载配置信息，以后如果配置服务器信息变化会通知到所有的 mongos 更新自己的状态，这样 mongos 就能继续准确路由。在生产环境通常有多个 config server 配置服务器，因为它存储了分片路由的元数据，这个可不能丢失！就算挂掉其中一台，只要还有存货， mongodb集群就不会挂掉。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>shard</strong>，这就是传说中的分片了。上面提到一个机器就算能力再大也有天花板，就像军队打仗一样，一个人再厉害喝血瓶也拼不过对方的一个师。俗话说三个臭皮匠顶个诸葛亮，这个时候团队的力量就凸显出来了。在互联网也是这样，一台普通的机器做不了的多台机器来做，如下图：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%88%86%E7%89%87/04.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;一台机器的一个数据表 Collection1 存储了 1T 数据，压力太大了！在分给4个机器后，每个机器都是256G，则分摊了集中在一台机器的压力。也许有人问一台机器硬盘加大一点不就可以了，为什么要分给四台机器呢？不要光想到存储空间，实际运行的数据库还有硬盘的读写、网络的IO、CPU和内存的瓶颈。在mongodb集群只要设置好了分片规则，通过mongos操作数据库就能自动把对应的数据操作请求转发到对应的分片机器上。在生产环境中分片的片键可要好好设置，这个影响到了怎么把数据均匀分到多个分片机器上，不要出现其中一台机器分了1T，其他机器没有分到的情况，这样还不如不分片！</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<strong>replica set</strong>，上两节已经详细讲过了这个东东，怎么这里又来凑热闹！其实上图4个分片如果没有 replica set 是个不完整架构，假设其中的一个分片挂掉那四分之一的数据就丢失了，所以在高可用性的分片架构还需要对于每一个分片构建 replica set 副本集保证分片的可靠性。生产环境通常是 2个副本 + 1个仲裁。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;说了这么多，还是来实战一下如何搭建高可用的mongodb集群：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;首先确定各个组件的数量，mongos 3个， config server 3个，数据分3片 shard server 3个，每个shard 有一个副本一个仲裁也就是 3 * 2 = 6 个，总共需要部署15个实例。这些实例可以部署在独立机器也可以部署在一台机器，我们这里测试资源有限，只准备了 3台机器，在同一台机器只要端口不同就可以，看一下物理部署图：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%88%86%E7%89%87/05.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;架构搭好了，安装软件！</p>
<ol>
<li><p>准备机器，IP分别设置为： 192.168.0.136、192.168.0.137、192.168.0.138。</p>
</li>
<li><p>分别在每台机器上建立mongodb分片对应测试文件夹。</p>
</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#存放mongodb数据文件</span></div><div class="line">mkdir -p /data/mongodbtest</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#进入mongodb文件夹</span></div><div class="line"><span class="built_in">cd</span> /data/mongodbtest</div></pre></td></tr></table></figure>
<ol>
<li>下载mongodb的安装程序包</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.8.tgz</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#解压下载的压缩包</span></div><div class="line">tar xvzf mongodb-linux-x86_64-2.4.8.tgz</div></pre></td></tr></table></figure>
<ol>
<li>分别在每台机器建立mongos 、config 、 shard1 、shard2、shard3 五个目录。<br>因为mongos不存储数据，只需要建立日志文件目录即可。</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立mongos目录</span></div><div class="line">mkdir -p /data/mongodbtest/mongos/<span class="built_in">log</span></div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立config server 数据文件存放目录</span></div><div class="line">mkdir -p /data/mongodbtest/config/data</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立config server 日志文件存放目录</span></div><div class="line">mkdir -p /data/mongodbtest/config/<span class="built_in">log</span></div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立config server 日志文件存放目录</span></div><div class="line">mkdir -p /data/mongodbtest/mongos/<span class="built_in">log</span></div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立shard1 数据文件存放目录</span></div><div class="line">mkdir -p /data/mongodbtest/shard1/data</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立shard1 日志文件存放目录</span></div><div class="line">mkdir -p /data/mongodbtest/shard1/<span class="built_in">log</span></div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立shard2 数据文件存放目录</span></div><div class="line">mkdir -p /data/mongodbtest/shard2/data</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立shard2 日志文件存放目录</span></div><div class="line">mkdir -p /data/mongodbtest/shard2/<span class="built_in">log</span></div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立shard3 数据文件存放目录</span></div><div class="line">mkdir -p /data/mongodbtest/shard3/data</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#建立shard3 日志文件存放目录</span></div><div class="line">mkdir -p /data/mongodbtest/shard3/<span class="built_in">log</span></div></pre></td></tr></table></figure>
<ol>
<li>规划5个组件对应的端口号，由于一个机器需要同时部署 mongos、config server 、shard1、shard2、shard3，所以需要用端口进行区分。</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;这个端口可以自由定义，在本文 mongos为 20000， config server 为 21000， shard1为 22001 ， shard2为22002， shard3为22003.</p>
<ol>
<li>在每一台服务器分别启动配置服务器。</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongod --configsvr --dbpath /data/mongodbtest/config/data --port 21000 --logpath /data/mongodbtest/config/<span class="built_in">log</span>/config.log --fork</div></pre></td></tr></table></figure>
<ol>
<li>在每一台服务器分别启动mongos服务器。</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongos --configdb 192.168.0.136:21000,192.168.0.137:21000,192.168.0.138:21000 --port 20000 --logpath  /data/mongodbtest/mongos/<span class="built_in">log</span>/mongos.log --fork</div></pre></td></tr></table></figure>
<ol>
<li>配置各个分片的副本集。</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#在每个机器里分别设置分片1服务器及副本集shard1</span></div><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongod --shardsvr --replSet shard1 --port 22001 --dbpath /data/mongodbtest/shard1/data --logpath /data/mongodbtest/shard1/<span class="built_in">log</span>/shard1.log --fork --nojournal --oplogSize 10</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;为了快速启动并节约测试环境存储空间，这里加上 nojournal 是为了关闭日志信息，在我们的测试环境不需要初始化这么大的redo日志。同样设置 oplogsize是为了降低 local 文件的大小，oplog是一个固定长度的 capped collection,它存在于”local”数据库中,用于记录Replica Sets操作日志。注意，这里的设置是为了测试！</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#在每个机器里分别设置分片2服务器及副本集shard2</span></div><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongod --shardsvr --replSet shard2 --port 22002 --dbpath /data/mongodbtest/shard2/data --logpath /data/mongodbtest/shard2/<span class="built_in">log</span>/shard2.log --fork --nojournal --oplogSize 10</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#在每个机器里分别设置分片3服务器及副本集shard3</span></div><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongod --shardsvr --replSet shard3 --port 22003 --dbpath /data/mongodbtest/shard3/data --logpath /data/mongodbtest/shard3/<span class="built_in">log</span>/shard3.log --fork --nojournal --oplogSize 10</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;分别对每个分片配置副本集，深入了解副本集参考本系列前几篇文章。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;任意登陆一个机器，比如登陆192.168.0.136，连接mongodb</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#设置第一个分片副本集</span></div><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo 127.0.0.1:22001</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#使用admin数据库</span></div><div class="line">use admin</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#定义副本集配置</span></div><div class="line">config = &#123; _id:<span class="string">"shard1"</span>, members:[</div><div class="line"> &#123;_id:0,host:<span class="string">"192.168.0.136:22001"</span>&#125;,</div><div class="line"> &#123;_id:1,host:<span class="string">"192.168.0.137:22001"</span>&#125;,</div><div class="line"> &#123;_id:2,host:<span class="string">"192.168.0.138:22001"</span>,arbiterOnly:<span class="literal">true</span>&#125;</div><div class="line"> ]</div><div class="line"> &#125;</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#初始化副本集配置</span></div><div class="line">rs.initiate(config);</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#设置第二个分片副本集</span></div><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo 127.0.0.1:22002</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#使用admin数据库</span></div><div class="line">use admin</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#定义副本集配置</span></div><div class="line">config = &#123; _id:<span class="string">"shard2"</span>, members:[</div><div class="line"> &#123;_id:0,host:<span class="string">"192.168.0.136:22002"</span>&#125;,</div><div class="line"> &#123;_id:1,host:<span class="string">"192.168.0.137:22002"</span>&#125;,</div><div class="line"> &#123;_id:2,host:<span class="string">"192.168.0.138:22002"</span>,arbiterOnly:<span class="literal">true</span>&#125;</div><div class="line"> ]</div><div class="line"> &#125;</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#初始化副本集配置</span></div><div class="line">rs.initiate(config);</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#设置第三个分片副本集</span></div><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo 127.0.0.1:22003</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#使用admin数据库</span></div><div class="line">use admin</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#定义副本集配置</span></div><div class="line">config = &#123; _id:<span class="string">"shard3"</span>, members:[</div><div class="line"> &#123;_id:0,host:<span class="string">"192.168.0.136:22003"</span>&#125;,</div><div class="line"> &#123;_id:1,host:<span class="string">"192.168.0.137:22003"</span>&#125;,</div><div class="line"> &#123;_id:2,host:<span class="string">"192.168.0.138:22003"</span>,arbiterOnly:<span class="literal">true</span>&#125;</div><div class="line"> ]</div><div class="line"> &#125;</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#初始化副本集配置</span></div><div class="line">rs.initiate(config);</div></pre></td></tr></table></figure>
<ol>
<li>目前搭建了mongodb配置服务器、路由服务器，各个分片服务器，不过应用程序连接到 mongos 路由服务器并不能使用分片机制，还需要在程序里设置分片配置，让分片生效。</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#连接到mongos</span></div><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo 127.0.0.1:20000</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#使用admin数据库</span></div><div class="line">user admin</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#串联路由服务器与分配副本集1</span></div><div class="line">db.runCommand( &#123; addshard : <span class="string">"shard1/192.168.0.136:22001,192.168.0.137:22001,192.168.0.138:22001"</span>&#125;);</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;如里shard是单台服务器，用 db.runCommand( { addshard : “[: ]” } )这样的命令加入，如果shard是副本集，用db.runCommand( { addshard : “replicaSetName/[:port][,serverhostname2[:port],…]” });这样的格式表示 。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#串联路由服务器与分配副本集2</span></div><div class="line">db.runCommand( &#123; addshard : <span class="string">"shard2/192.168.0.136:22002,192.168.0.137:22002,192.168.0.138:22002"</span>&#125;);</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#串联路由服务器与分配副本集3</span></div><div class="line">db.runCommand( &#123; addshard : <span class="string">"shard3/192.168.0.136:22003,192.168.0.137:22003,192.168.0.138:22003"</span>&#125;);</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#查看分片服务器的配置</span></div><div class="line">db.runCommand( &#123; listshards : 1 &#125; );</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;内容输出</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line"> <span class="string">"shards"</span> : [</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : <span class="string">"shard1"</span>,</div><div class="line"> <span class="string">"host"</span> : <span class="string">"shard1/192.168.0.136:22001,192.168.0.137:22001"</span></div><div class="line"> &#125;,</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : <span class="string">"shard2"</span>,</div><div class="line"> <span class="string">"host"</span> : <span class="string">"shard2/192.168.0.136:22002,192.168.0.137:22002"</span></div><div class="line"> &#125;,</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : <span class="string">"shard3"</span>,</div><div class="line"> <span class="string">"host"</span> : <span class="string">"shard3/192.168.0.136:22003,192.168.0.137:22003"</span></div><div class="line"> &#125;</div><div class="line"> ],</div><div class="line"> <span class="string">"ok"</span> : 1</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;因为192.168.0.138是每个分片副本集的仲裁节点，所以在上面结果没有列出来。</p>
<ol>
<li>目前配置服务、路由服务、分片服务、副本集服务都已经串联起来了，但我们的目的是希望插入数据，数据能够自动分片，就差那么一点点，一点点。。。</li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;连接在mongos上，准备让指定的数据库、指定的集合分片生效。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#指定testdb分片生效</span></div><div class="line">db.runCommand( &#123; enablesharding :<span class="string">"testdb"</span>&#125;);</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#指定数据库里需要分片的集合和片键</span></div><div class="line">db.runCommand( &#123; shardcollection : <span class="string">"testdb.table1"</span>,key : &#123;id: 1&#125; &#125; )</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;我们设置testdb的 table1 表需要分片，根据 id 自动分片到 shard1 ，shard2，shard3 上面去。要这样设置是因为不是所有mongodb 的数据库和表 都需要分片！</p>
<ol>
<li>测试分片配置结果。</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#连接mongos服务器</span></div><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo 127.0.0.1:20000</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#使用testdb</span></div><div class="line">use testdb;</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#插入测试数据</span></div><div class="line"><span class="keyword">for</span> (var i = 1; i &lt;= 100000; i++)</div><div class="line">db.table1.save(&#123;id:i,<span class="string">"test1"</span>:<span class="string">"testval1"</span>&#125;);</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#查看分片情况如下，部分无关信息省掉了</span></div><div class="line">db.table1.stats();</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line"> <span class="string">"sharded"</span> : <span class="literal">true</span>,</div><div class="line"> <span class="string">"ns"</span> : <span class="string">"testdb.table1"</span>,</div><div class="line"> <span class="string">"count"</span> : 100000,</div><div class="line"> <span class="string">"numExtents"</span> : 13,</div><div class="line"> <span class="string">"size"</span> : 5600000,</div><div class="line"> <span class="string">"storageSize"</span> : 22372352,</div><div class="line"> <span class="string">"totalIndexSize"</span> : 6213760,</div><div class="line"> <span class="string">"indexSizes"</span> : &#123;</div><div class="line"> <span class="string">"_id_"</span> : 3335808,</div><div class="line"> <span class="string">"id_1"</span> : 2877952</div><div class="line"> &#125;,</div><div class="line"> <span class="string">"avgObjSize"</span> : 56,</div><div class="line"> <span class="string">"nindexes"</span> : 2,</div><div class="line"> <span class="string">"nchunks"</span> : 3,</div><div class="line"> <span class="string">"shards"</span> : &#123;</div><div class="line"> <span class="string">"shard1"</span> : &#123;</div><div class="line"> <span class="string">"ns"</span> : <span class="string">"testdb.table1"</span>,</div><div class="line"> <span class="string">"count"</span> : 42183,</div><div class="line"> <span class="string">"size"</span> : 0,</div><div class="line"> ...</div><div class="line"> <span class="string">"ok"</span> : 1</div><div class="line"> &#125;,</div><div class="line"> <span class="string">"shard2"</span> : &#123;</div><div class="line"> <span class="string">"ns"</span> : <span class="string">"testdb.table1"</span>,</div><div class="line"> <span class="string">"count"</span> : 38937,</div><div class="line"> <span class="string">"size"</span> : 2180472,</div><div class="line"> ...</div><div class="line"> <span class="string">"ok"</span> : 1</div><div class="line"> &#125;,</div><div class="line"> <span class="string">"shard3"</span> : &#123;</div><div class="line"> <span class="string">"ns"</span> : <span class="string">"testdb.table1"</span>,</div><div class="line"> <span class="string">"count"</span> :18880,</div><div class="line"> <span class="string">"size"</span> : 3419528,</div><div class="line"> ...</div><div class="line"> <span class="string">"ok"</span> : 1</div><div class="line"> &#125;</div><div class="line"> &#125;,</div><div class="line"> <span class="string">"ok"</span> : 1</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可以看到数据分到3个分片，各自分片数量为： shard1 “count” : 42183，shard2  “count” : 38937，shard3 “count” : 18880。已经成功了！不过分的好像不是很均 匀，所以这个分片还是很有讲究的，后续再深入讨论。</p>
<ol>
<li>java程序调用分片集群，因为我们配置了三个mongos作为入口，就算其中哪个入口挂掉了都没关系，使用集群客户端程序如下：</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line">public class TestMongoDBShards &#123;</div><div class="line"> </div><div class="line"> public static void main(String[] args) &#123;</div><div class="line"> </div><div class="line"> try &#123;</div><div class="line"> List&lt;ServerAddress&gt; addresses = new ArrayList&lt;ServerAddress&gt;();</div><div class="line"> ServerAddress address1 = new ServerAddress(<span class="string">"192.168.0.136"</span> , 20000);</div><div class="line"> ServerAddress address2 = new ServerAddress(<span class="string">"192.168.0.137"</span> , 20000);</div><div class="line"> ServerAddress address3 = new ServerAddress(<span class="string">"192.168.0.138"</span> , 20000);</div><div class="line"> addresses.add(address1);</div><div class="line"> addresses.add(address2);</div><div class="line"> addresses.add(address3);</div><div class="line"> </div><div class="line"> MongoClient client = new MongoClient(addresses);</div><div class="line"> DB db = client.getDB( <span class="string">"testdb"</span> );</div><div class="line"> DBCollection coll = db.getCollection( <span class="string">"table1"</span> );</div><div class="line"> </div><div class="line"> BasicDBObject object = new BasicDBObject();</div><div class="line"> object.append( <span class="string">"id"</span> , 1);</div><div class="line"> </div><div class="line"> DBObject dbObject = coll.findOne(object);</div><div class="line"> </div><div class="line"> System. out .println(dbObject);</div><div class="line"> </div><div class="line"> &#125; catch (Exception e) &#123;</div><div class="line"> e.printStackTrace();</div><div class="line"> &#125;</div><div class="line"> &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;整个分片集群搭建完了，思考一下我们这个架构是不是足够好呢？其实还有很多地方需要优化，比如我们把所有的仲裁节点放在一台机器，其余两台机器承担了全部读写操作，但是作为仲裁的192.168.0.138相当空闲。让机器3 192.168.0.138多分担点责任吧！架构可以这样调整，把机器的负载分的更加均衡一点，每个机器既可以作为主节点、副本节点、仲裁节点，这样压力就会均衡很多了，如图：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%88%86%E7%89%87/06.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;当然生产环境的数据远远大于当前的测试数据，大规模数据应用情况下我们不可能把全部的节点像这样部署，硬件瓶颈是硬伤，只能扩展机器。要用好mongodb还有很多机制需要调整，不过通过这个东东我们可以快速实现高可用性、高扩展性，所以它还是一个非常不错的Nosql组件。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;再看看我们使用的mongodb java 驱动客户端 MongoClient(addresses)，这个可以传入多个mongos 的地址作为mongodb集群的入口，并且可以实现自动故障转移，但是负载均衡做的好不好呢？打开源代码查看：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%88%86%E7%89%87/07.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;它的机制是选择一个ping 最快的机器来作为所有请求的入口，如果这台机器挂掉会使用下一台机器。那这样。。。。肯定是不行的！万一出现双十一这样的情况所有请求集中发送到这一台机器，这台机器很有可能挂掉。一但挂掉了，按照它的机制会转移请求到下台机器，但是这个压力总量还是没有减少啊！下一台还是可能崩溃，所以这个架构还有漏洞！不过这个文章已经太长了，后续解决吧。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;参考：<a href="http://docs.mongodb.org/manual/core/sharding-introduction/" target="_blank" rel="external">http://docs.mongodb.org/manual/core/sharding-introduction/</a></p>

	

	

</article>




	<article>
	
		<h1><a href="/2017/10/12/MongoDB/15. 搭建高可用mongodb集群—— 副本集/">搭建高可用mongodb集群—— 副本集</a></h1>
	
	<div class="article__infos">
		<span class="article__date">2017-10-12</span><br />
		
		
			<span class="article__tags">
			  	<a class="article__tag-link" href="/tags/MongoDB/">MongoDB</a>
			</span>
		
	</div>

	

	
		<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在<a href="">搭建高可用mongodb集群——配置mongodb</a>提到了几个问题还没有解决。</p>
<ul>
<li>主节点挂了能否自动切换连接？目前需要手工切换。</li>
<li>主节点的读写压力过大如何解决？</li>
<li>从节点每个上面的数据都是对数据库全量拷贝，从节点压力会不会过大？</li>
<li>数据压力大到机器支撑不了的时候能否做到自动扩展？</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;NoSQL的产生就是为了解决大数据量、高扩展性、高性能、灵活数据模型、高可用性。但是光通过主从模式的架构远远达不到上面几点，由此MongoDB设计了副本集和分片的功能。这篇文章主要介绍<strong>副本集</strong>：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;mongoDB官方已经<strong>不建议使用主从模式了</strong>，替代方案是采用副本集的模式，<a href="https://docs.mongodb.com/master/core/master-slave/" target="_blank" rel="external">点击查看</a> ，如图：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%89%AF%E6%9C%AC%E9%9B%86/01.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;那什么是副本集呢？打魔兽世界总说打副本，其实这两个概念差不多一个意思。游戏里的副本是指玩家集中在高峰时间去一个场景打怪，会出现玩家暴多怪物少的情况，游戏开发商为了保证玩家的体验度，就为每一批玩家单独开放一个同样的空间同样的数量的怪物，这一个复制的场景就是一个副本，不管有多少个玩家各自在各自的副本里玩不会互相  影响。 mongoDB的副本也是这个，主从模式其实就是一个单副本的应用，没有很好的扩展 性和容错性。而副本集具有多个副本保证了容错性，就算一个副本挂掉了还有很多副本存 在，并且解决了上面第一个问题“主节点挂掉了，整个集群内会自动切换”。难怪mongoDB  官方推荐使用这种模式。我们来看看mongoDB副本集的架构图：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%89%AF%E6%9C%AC%E9%9B%86/02.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;由图可以看到客户端连接到整个副本集，不关心具体哪一台机器是否挂掉。主服务器负责整个副本集的读写，副本集定期同步数据备份，一但主节点挂掉，副本节点就会选举一个新的主服务器，这一切对于应用服务器不需要关心。我们看一下主服务器挂掉后的架构：</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%89%AF%E6%9C%AC%E9%9B%86/03.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;副本集中的副本节点在主节点挂掉后通过心跳机制检测到后，就会在集群内发起主节点的选举机制，自动选举一位新的主服务器。看起来很牛X的样子，我们赶紧操作部署一下！</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;官方推荐的副本集机器数量为至少3个，那我们也按照这个数量配置测试。</p>
<ol>
<li><p><strong>准备两台机器</strong> 192.168.1.136、192.168.1.137、192.168.1.138。 192.168.1.136 当作副本集<strong>主节点</strong>，192.168.1.137、192.168.1.138作为副本集<strong>副本节点</strong>。</p>
</li>
<li><p><strong>分别在每台机器上建立mongodb副本集测试文件夹</strong></p>
</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#存放整个mongodb文件</span></div><div class="line">mkdir -p /data/mongodbtest/replset</div><div class="line"> </div><div class="line"><span class="comment">#存放mongodb数据文件</span></div><div class="line">mkdir -p /data/mongodbtest/replset/data</div><div class="line"> </div><div class="line"><span class="comment">#进入mongodb文件夹</span></div><div class="line"><span class="built_in">cd</span> /data/mongodbtest</div></pre></td></tr></table></figure>
<ol>
<li><strong>下载mongodb的安装程序包</strong></li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.8.tgz</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;注意linux生产环境不能安装32位的mongodb，因为32位受限于操作系统最大2G的文件限制。</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%89%AF%E6%9C%AC%E9%9B%86/04.png?raw=true" alt=""></figure></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#解压下载的压缩包 </span></div><div class="line">tar xvzf mongodb-linux-x86_64-2.4.8.tgz</div></pre></td></tr></table></figure>
<ol>
<li><strong>分别在每台机器上启动mongodb</strong></li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongod --dbpath /data/mongodbtest/replset/data --replSet repset</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;可以看到控制台上显示副本集还没有配置初始化信息。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">Sun Dec 29 20:12:02.953 [rsStart] replSet can<span class="string">'t get local.system.replset config from self or any seed (EMPTYCONFIG)</span></div><div class="line"><span class="string">Sun Dec 29 20:12:02.953 [rsStart] replSet info you may need to run replSetInitiate -- rs.initiate() in the shell -- if that is not already done</span></div></pre></td></tr></table></figure>
<ol>
<li><strong>初始化副本集</strong></li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;在三台机器上任意一台机器登陆mongodb</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo</div><div class="line"> </div><div class="line"><span class="comment">#使用admin数据库</span></div><div class="line">use admin</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;定义副本集配置变量，这里的 _id:”repset” 和上面命令参数“ –replSet repset” 要保持一样。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">config = &#123; _id:<span class="string">"repset"</span>, members:[</div><div class="line">... &#123;_id:0,host:<span class="string">"192.168.1.136:27017"</span>&#125;,</div><div class="line">... &#123;_id:1,host:<span class="string">"192.168.1.137:27017"</span>&#125;,</div><div class="line">... &#123;_id:2,host:<span class="string">"192.168.1.138:27017"</span>&#125;]</div><div class="line">... &#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;输出</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line"> <span class="string">"_id"</span> : <span class="string">"repset"</span>,</div><div class="line"> <span class="string">"members"</span> : [</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : 0,</div><div class="line"> <span class="string">"host"</span> : <span class="string">"192.168.1.136:27017"</span></div><div class="line"> &#125;,</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : 1,</div><div class="line"> <span class="string">"host"</span> : <span class="string">"192.168.1.137:27017"</span></div><div class="line"> &#125;,</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : 2,</div><div class="line"> <span class="string">"host"</span> : <span class="string">"192.168.1.138:27017"</span></div><div class="line"> &#125;</div><div class="line"> ]</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#初始化副本集配置</span></div><div class="line">rs.initiate(config);</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;输出成功</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line"> <span class="string">"info"</span> : <span class="string">"Config now saved locally. Should come online in about a minute."</span>,</div><div class="line"> <span class="string">"ok"</span> : 1</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;查看日志，副本集启动成功后，138为主节点<strong>PRIMARY</strong>，136、137为副本节点<strong>SECONDARY</strong>。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line">Sun Dec 29 20:26:13.842 [conn3] replSet replSetInitiate admin <span class="built_in">command</span> received from client</div><div class="line">Sun Dec 29 20:26:13.842 [conn3] replSet replSetInitiate config object parses ok, 3 members specified</div><div class="line">Sun Dec 29 20:26:13.847 [conn3] replSet replSetInitiate all members seem up</div><div class="line">Sun Dec 29 20:26:13.848 [conn3] ******</div><div class="line">Sun Dec 29 20:26:13.848 [conn3] creating replication oplog of size: 990MB...</div><div class="line">Sun Dec 29 20:26:13.849 [FileAllocator] allocating new datafile /data/mongodbtest/replset/data/local.1, filling with zeroes...</div><div class="line">Sun Dec 29 20:26:13.862 [FileAllocator] <span class="keyword">done</span> allocating datafile /data/mongodbtest/replset/data/local.1, size: 1024MB, took 0.012 secs</div><div class="line">Sun Dec 29 20:26:13.863 [conn3] ******</div><div class="line">Sun Dec 29 20:26:13.863 [conn3] replSet info saving a newer config version to local.system.replset</div><div class="line">Sun Dec 29 20:26:13.864 [conn3] replSet saveConfigLocally <span class="keyword">done</span></div><div class="line">Sun Dec 29 20:26:13.864 [conn3] replSet replSetInitiate config now saved locally. Should come online <span class="keyword">in</span> about a minute.</div><div class="line">Sun Dec 29 20:26:23.047 [rsStart] replSet I am 192.168.1.138:27017</div><div class="line">Sun Dec 29 20:26:23.048 [rsStart] replSet STARTUP2</div><div class="line">Sun Dec 29 20:26:23.049 [rsHealthPoll] replSet member 192.168.1.137:27017 is up</div><div class="line">Sun Dec 29 20:26:23.049 [rsHealthPoll] replSet member 192.168.1.136:27017 is up</div><div class="line">Sun Dec 29 20:26:24.051 [rsSync] replSet SECONDARY</div><div class="line">Sun Dec 29 20:26:25.053 [rsHealthPoll] replset info 192.168.1.136:27017 thinks that we are down</div><div class="line">Sun Dec 29 20:26:25.053 [rsHealthPoll] replSet member 192.168.1.136:27017 is now <span class="keyword">in</span> state STARTUP2</div><div class="line">Sun Dec 29 20:26:25.056 [rsMgr] not electing self, 192.168.1.136:27017 would veto with <span class="string">'I don'</span>t think 192.168.1.138:27017 is electable<span class="string">'</span></div><div class="line"><span class="string">Sun Dec 29 20:26:31.059 [rsHealthPoll] replset info 192.168.1.137:27017 thinks that we are down</span></div><div class="line"><span class="string">Sun Dec 29 20:26:31.059 [rsHealthPoll] replSet member 192.168.1.137:27017 is now in state STARTUP2</span></div><div class="line"><span class="string">Sun Dec 29 20:26:31.062 [rsMgr] not electing self, 192.168.1.137:27017 would veto with '</span>I don<span class="string">'t think 192.168.1.138:27017 is electable'</span></div><div class="line">Sun Dec 29 20:26:37.074 [rsMgr] replSet info electSelf 2</div><div class="line">Sun Dec 29 20:26:38.062 [rsMgr] replSet PRIMARY</div><div class="line">Sun Dec 29 20:26:39.071 [rsHealthPoll] replSet member 192.168.1.137:27017 is now <span class="keyword">in</span> state RECOVERING</div><div class="line">Sun Dec 29 20:26:39.075 [rsHealthPoll] replSet member 192.168.1.136:27017 is now <span class="keyword">in</span> state RECOVERING</div><div class="line">Sun Dec 29 20:26:42.201 [slaveTracking] build index local.slaves &#123; _id: 1 &#125;</div><div class="line">Sun Dec 29 20:26:42.207 [slaveTracking] build index <span class="keyword">done</span>. scanned 0 total records. 0.005 secs</div><div class="line">Sun Dec 29 20:26:43.079 [rsHealthPoll] replSet member 192.168.1.136:27017 is now <span class="keyword">in</span> state SECONDARY</div><div class="line">Sun Dec 29 20:26:49.080 [rsHealthPoll] replSet member 192.168.1.137:27017 is now <span class="keyword">in</span> state SECONDARY</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#查看集群节点的状态</span></div><div class="line"> rs.status();</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;输出</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line"> <span class="string">"set"</span> : <span class="string">"repset"</span>,</div><div class="line"> <span class="string">"date"</span> : ISODate(<span class="string">"2013-12-29T12:54:25Z"</span>),</div><div class="line"> <span class="string">"myState"</span> : 1,</div><div class="line"> <span class="string">"members"</span> : [</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : 0,</div><div class="line"> <span class="string">"name"</span> : <span class="string">"192.168.1.136:27017"</span>,</div><div class="line"> <span class="string">"health"</span> : 1,</div><div class="line"> <span class="string">"state"</span> : 2,</div><div class="line"> <span class="string">"stateStr"</span> : <span class="string">"SECONDARY"</span>,</div><div class="line"> <span class="string">"uptime"</span> : 1682,</div><div class="line"> <span class="string">"optime"</span> : Timestamp(1388319973, 1),</div><div class="line"> <span class="string">"optimeDate"</span> : ISODate(<span class="string">"2013-12-29T12:26:13Z"</span>),</div><div class="line"> <span class="string">"lastHeartbeat"</span> : ISODate(<span class="string">"2013-12-29T12:54:25Z"</span>),</div><div class="line"> <span class="string">"lastHeartbeatRecv"</span> : ISODate(<span class="string">"2013-12-29T12:54:24Z"</span>),</div><div class="line"> <span class="string">"pingMs"</span> : 1,</div><div class="line"> <span class="string">"syncingTo"</span> : <span class="string">"192.168.1.138:27017"</span></div><div class="line"> &#125;,</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : 1,</div><div class="line"> <span class="string">"name"</span> : <span class="string">"192.168.1.137:27017"</span>,</div><div class="line"> <span class="string">"health"</span> : 1,</div><div class="line"> <span class="string">"state"</span> : 2,</div><div class="line"> <span class="string">"stateStr"</span> : <span class="string">"SECONDARY"</span>,</div><div class="line"> <span class="string">"uptime"</span> : 1682,</div><div class="line"> <span class="string">"optime"</span> : Timestamp(1388319973, 1),</div><div class="line"> <span class="string">"optimeDate"</span> : ISODate(<span class="string">"2013-12-29T12:26:13Z"</span>),</div><div class="line"> <span class="string">"lastHeartbeat"</span> : ISODate(<span class="string">"2013-12-29T12:54:25Z"</span>),</div><div class="line"> <span class="string">"lastHeartbeatRecv"</span> : ISODate(<span class="string">"2013-12-29T12:54:24Z"</span>),</div><div class="line"> <span class="string">"pingMs"</span> : 1,</div><div class="line"> <span class="string">"syncingTo"</span> : <span class="string">"192.168.1.138:27017"</span></div><div class="line"> &#125;,</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : 2,</div><div class="line"> <span class="string">"name"</span> : <span class="string">"192.168.1.138:27017"</span>,</div><div class="line"> <span class="string">"health"</span> : 1,</div><div class="line"> <span class="string">"state"</span> : 1,</div><div class="line"> <span class="string">"stateStr"</span> : <span class="string">"PRIMARY"</span>,</div><div class="line"> <span class="string">"uptime"</span> : 2543,</div><div class="line"> <span class="string">"optime"</span> : Timestamp(1388319973, 1),</div><div class="line"> <span class="string">"optimeDate"</span> : ISODate(<span class="string">"2013-12-29T12:26:13Z"</span>),</div><div class="line"> <span class="string">"self"</span> : <span class="literal">true</span></div><div class="line"> &#125;</div><div class="line"> ],</div><div class="line"> <span class="string">"ok"</span> : 1</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;整个副本集已经搭建成功了。</p>
<ol>
<li><strong>测试副本集数据复制功能</strong></li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#在主节点192.168.1.138 上连接到终端：</span></div><div class="line">mongo 127.0.0.1</div><div class="line"> </div><div class="line"><span class="comment">#建立test 数据库。</span></div><div class="line">use <span class="built_in">test</span>;</div><div class="line"> </div><div class="line">往testdb表插入数据。</div><div class="line">&gt; db.testdb.insert(&#123;<span class="string">"test1"</span>:<span class="string">"testval1"</span>&#125;)</div><div class="line"> </div><div class="line"><span class="comment">#在副本节点 192.168.1.136、192.168.1.137 上连接到mongodb查看数据是否复制过来。</span></div><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo 192.168.1.136:27017</div><div class="line"> </div><div class="line"><span class="comment">#使用test 数据库。</span></div><div class="line">repset:SECONDARY&gt; use <span class="built_in">test</span>;</div><div class="line"> </div><div class="line">repset:SECONDARY&gt; show tables;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;输出</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Sun Dec 29 21:50:48.590 error: &#123; <span class="string">"<span class="variable">$err</span>"</span> : <span class="string">"not master and slaveOk=false"</span>, <span class="string">"code"</span> : 13435 &#125; at src/mongo/shell/query.js:128</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#mongodb默认是从主节点读写数据的，副本节点上不允许读，需要设置副本节点可以读。</span></div><div class="line">repset:SECONDARY&gt; db.getMongo().setSlaveOk();</div><div class="line"> </div><div class="line"><span class="comment">#可以看到数据已经复制到了副本集。</span></div><div class="line">repset:SECONDARY&gt; db.testdb.find();</div></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment">#输出</span></div><div class="line">&#123; <span class="string">"_id"</span> : ObjectId(<span class="string">"52c028460c7505626a93944f"</span>), <span class="string">"test1"</span> : <span class="string">"testval1"</span> &#125;</div></pre></td></tr></table></figure>
<ol>
<li><strong>测试副本集故障转移功能</strong></li>
</ol>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;先停掉主节点mongodb 138，查看136、137的日志可以看到经过一系列的投票选择操作，137 当选主节点，136从137同步数据过来。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">Sun Dec 29 22:03:05.351 [rsBackgroundSync] replSet sync <span class="built_in">source</span> problem: 10278 dbclient error communicating with server: 192.168.1.138:27017</div><div class="line">Sun Dec 29 22:03:05.354 [rsBackgroundSync] replSet syncing to: 192.168.1.138:27017</div><div class="line">Sun Dec 29 22:03:05.356 [rsBackgroundSync] repl: couldn<span class="string">'t connect to server 192.168.1.138:27017</span></div><div class="line"><span class="string">Sun Dec 29 22:03:05.356 [rsBackgroundSync] replSet not trying to sync from 192.168.1.138:27017, it is vetoed for 10 more seconds</span></div><div class="line"><span class="string">Sun Dec 29 22:03:05.499 [rsHealthPoll] DBClientCursor::init call() failed</span></div><div class="line"><span class="string">Sun Dec 29 22:03:05.499 [rsHealthPoll] replset info 192.168.1.138:27017 heartbeat failed, retrying</span></div><div class="line"><span class="string">Sun Dec 29 22:03:05.501 [rsHealthPoll] replSet info 192.168.1.138:27017 is down (or slow to respond):</span></div><div class="line"><span class="string">Sun Dec 29 22:03:05.501 [rsHealthPoll] replSet member 192.168.1.138:27017 is now in state DOWN</span></div><div class="line"><span class="string">Sun Dec 29 22:03:05.511 [rsMgr] not electing self, 192.168.1.137:27017 would veto with '</span>192.168.1.136:27017 is trying to elect itself but 192.168.1.138:27017 is already primary and more up-to-date<span class="string">'</span></div><div class="line"><span class="string">Sun Dec 29 22:03:07.330 [conn393] replSet info voting yea for 192.168.1.137:27017 (1)</span></div><div class="line"><span class="string">Sun Dec 29 22:03:07.503 [rsHealthPoll] replset info 192.168.1.138:27017 heartbeat failed, retrying</span></div><div class="line"><span class="string">Sun Dec 29 22:03:08.462 [rsHealthPoll] replSet member 192.168.1.137:27017 is now in state PRIMARY</span></div><div class="line"><span class="string">Sun Dec 29 22:03:09.359 [rsBackgroundSync] replSet syncing to: 192.168.1.137:27017</span></div><div class="line"><span class="string">Sun Dec 29 22:03:09.507 [rsHealthPoll] replset info 192.168.1.138:27017 heartbeat failed, retrying</span></div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;查看整个集群的状态，可以看到138为状态不可达。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">/data/mongodbtest/mongodb-linux-x86_64-2.4.8/bin/mongo 192.168.1.136:27017</div><div class="line"> </div><div class="line">repset:SECONDARY&gt; rs.status();</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;输出</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div></pre></td><td class="code"><pre><div class="line">&#123;</div><div class="line"> <span class="string">"set"</span> : <span class="string">"repset"</span>,</div><div class="line"> <span class="string">"date"</span> : ISODate(<span class="string">"2013-12-29T14:28:35Z"</span>),</div><div class="line"> <span class="string">"myState"</span> : 2,</div><div class="line"> <span class="string">"syncingTo"</span> : <span class="string">"192.168.1.137:27017"</span>,</div><div class="line"> <span class="string">"members"</span> : [</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : 0,</div><div class="line"> <span class="string">"name"</span> : <span class="string">"192.168.1.136:27017"</span>,</div><div class="line"> <span class="string">"health"</span> : 1,</div><div class="line"> <span class="string">"state"</span> : 2,</div><div class="line"> <span class="string">"stateStr"</span> : <span class="string">"SECONDARY"</span>,</div><div class="line"> <span class="string">"uptime"</span> : 9072,</div><div class="line"> <span class="string">"optime"</span> : Timestamp(1388324934, 1),</div><div class="line"> <span class="string">"optimeDate"</span> : ISODate(<span class="string">"2013-12-29T13:48:54Z"</span>),</div><div class="line"> <span class="string">"self"</span> : <span class="literal">true</span></div><div class="line"> &#125;,</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : 1,</div><div class="line"> <span class="string">"name"</span> : <span class="string">"192.168.1.137:27017"</span>,</div><div class="line"> <span class="string">"health"</span> : 1,</div><div class="line"> <span class="string">"state"</span> : 1,</div><div class="line"> <span class="string">"stateStr"</span> : <span class="string">"PRIMARY"</span>,</div><div class="line"> <span class="string">"uptime"</span> : 7329,</div><div class="line"> <span class="string">"optime"</span> : Timestamp(1388324934, 1),</div><div class="line"> <span class="string">"optimeDate"</span> : ISODate(<span class="string">"2013-12-29T13:48:54Z"</span>),</div><div class="line"> <span class="string">"lastHeartbeat"</span> : ISODate(<span class="string">"2013-12-29T14:28:34Z"</span>),</div><div class="line"> <span class="string">"lastHeartbeatRecv"</span> : ISODate(<span class="string">"2013-12-29T14:28:34Z"</span>),</div><div class="line"> <span class="string">"pingMs"</span> : 1,</div><div class="line"> <span class="string">"syncingTo"</span> : <span class="string">"192.168.1.138:27017"</span></div><div class="line"> &#125;,</div><div class="line"> &#123;</div><div class="line"> <span class="string">"_id"</span> : 2,</div><div class="line"> <span class="string">"name"</span> : <span class="string">"192.168.1.138:27017"</span>,</div><div class="line"> <span class="string">"health"</span> : 0,</div><div class="line"> <span class="string">"state"</span> : 8,</div><div class="line"> <span class="string">"stateStr"</span> : <span class="string">"(not reachable/healthy)"</span>,</div><div class="line"> <span class="string">"uptime"</span> : 0,</div><div class="line"> <span class="string">"optime"</span> : Timestamp(1388324934, 1),</div><div class="line"> <span class="string">"optimeDate"</span> : ISODate(<span class="string">"2013-12-29T13:48:54Z"</span>),</div><div class="line"> <span class="string">"lastHeartbeat"</span> : ISODate(<span class="string">"2013-12-29T14:28:35Z"</span>),</div><div class="line"> <span class="string">"lastHeartbeatRecv"</span> : ISODate(<span class="string">"2013-12-29T14:28:23Z"</span>),</div><div class="line"> <span class="string">"pingMs"</span> : 0,</div><div class="line"> <span class="string">"syncingTo"</span> : <span class="string">"192.168.1.137:27017"</span></div><div class="line"> &#125;</div><div class="line"> ],</div><div class="line"> <span class="string">"ok"</span> : 1</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;再启动原来的主节点 138，发现138 变为 SECONDARY，还是137 为主节点 PRIMARY。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">Sun Dec 29 22:21:06.619 [rsStart] replSet I am 192.168.1.138:27017</div><div class="line">Sun Dec 29 22:21:06.619 [rsStart] replSet STARTUP2</div><div class="line">Sun Dec 29 22:21:06.627 [rsHealthPoll] replset info 192.168.1.136:27017 thinks that we are down</div><div class="line">Sun Dec 29 22:21:06.627 [rsHealthPoll] replSet member 192.168.1.136:27017 is up</div><div class="line">Sun Dec 29 22:21:06.627 [rsHealthPoll] replSet member 192.168.1.136:27017 is now <span class="keyword">in</span> state SECONDARY</div><div class="line">Sun Dec 29 22:21:07.628 [rsSync] replSet SECONDARY</div><div class="line">Sun Dec 29 22:21:08.623 [rsHealthPoll] replSet member 192.168.1.137:27017 is up</div><div class="line">Sun Dec 29 22:21:08.624 [rsHealthPoll] replSet member 192.168.1.137:27017 is now <span class="keyword">in</span> state PRIMARY</div></pre></td></tr></table></figure>
<ol>
<li><strong>java程序连接副本集测试</strong>。三个节点有一个节点挂掉也不会影响应用程序客户端对整个副本集的读写！</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line">public class TestMongoDBReplSet &#123;</div><div class="line"> </div><div class="line"> public static void main(String[] args) &#123;</div><div class="line"> </div><div class="line"> try &#123;</div><div class="line"> List&lt;ServerAddress&gt; addresses = new ArrayList&lt;ServerAddress&gt;();</div><div class="line"> ServerAddress address1 = new ServerAddress(<span class="string">"192.168.1.136"</span> , 27017);</div><div class="line"> ServerAddress address2 = new ServerAddress(<span class="string">"192.168.1.137"</span> , 27017);</div><div class="line"> ServerAddress address3 = new ServerAddress(<span class="string">"192.168.1.138"</span> , 27017);</div><div class="line"> addresses.add(address1);</div><div class="line"> addresses.add(address2);</div><div class="line"> addresses.add(address3);</div><div class="line"> </div><div class="line"> MongoClient client = new MongoClient(addresses);</div><div class="line"> DB db = client.getDB( <span class="string">"test"</span>);</div><div class="line"> DBCollection coll = db.getCollection( <span class="string">"testdb"</span>);</div><div class="line"> </div><div class="line"> // 插入</div><div class="line"> BasicDBObject object = new BasicDBObject();</div><div class="line"> object.append( <span class="string">"test2"</span>, <span class="string">"testval2"</span> );</div><div class="line"> </div><div class="line"> coll.insert(object);</div><div class="line"> </div><div class="line"> DBCursor dbCursor = coll.find();</div><div class="line"> </div><div class="line"> <span class="keyword">while</span> (dbCursor.hasNext()) &#123;</div><div class="line"> DBObject dbObject = dbCursor.next();</div><div class="line"> System. out.println(dbObject.toString());</div><div class="line"> &#125;</div><div class="line"> </div><div class="line"> &#125; catch (Exception e) &#123;</div><div class="line"> e.printStackTrace();</div><div class="line"> &#125;</div><div class="line"> </div><div class="line"> &#125;</div><div class="line"> </div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;目前看起来支持完美的故障转移了，这个架构是不是比较完美了？其实还有很多地方可以优化，比如开头的第二个问题：主节点的读写压力过大如何解决？常见的解决方案是读写分离，mongodb副本集的读写分离如何做呢？</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%89%AF%E6%9C%AC%E9%9B%86/05.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;常规写操作来说并没有读操作多，所以一台主节点负责写，两台副本节点负责读。</p>
<ol>
<li><p>设置读写分离需要先在副本节点SECONDARY 设置 setSlaveOk。</p>
</li>
<li><p>在程序中设置副本节点负责读操作，如下代码：</p>
</li>
</ol>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line">public class TestMongoDBReplSetReadSplit &#123;</div><div class="line"> </div><div class="line"> public static void main(String[] args) &#123;</div><div class="line"> </div><div class="line"> try &#123;</div><div class="line"> List&lt;ServerAddress&gt; addresses = new ArrayList&lt;ServerAddress&gt;();</div><div class="line"> ServerAddress address1 = new ServerAddress(<span class="string">"192.168.1.136"</span> , 27017);</div><div class="line"> ServerAddress address2 = new ServerAddress(<span class="string">"192.168.1.137"</span> , 27017);</div><div class="line"> ServerAddress address3 = new ServerAddress(<span class="string">"192.168.1.138"</span> , 27017);</div><div class="line"> addresses.add(address1);</div><div class="line"> addresses.add(address2);</div><div class="line"> addresses.add(address3);</div><div class="line"> </div><div class="line"> MongoClient client = new MongoClient(addresses);</div><div class="line"> DB db = client.getDB( <span class="string">"test"</span> );</div><div class="line"> DBCollection coll = db.getCollection( <span class="string">"testdb"</span> );</div><div class="line"> </div><div class="line"> </div><div class="line"> BasicDBObject object = new BasicDBObject();</div><div class="line"> object.append( <span class="string">"test2"</span> , <span class="string">"testval2"</span> );</div><div class="line"> </div><div class="line"> //读操作从副本节点读取</div><div class="line"> ReadPreference preference = ReadPreference. secondary();</div><div class="line"> DBObject dbObject = coll.findOne(object, null , preference);</div><div class="line"> </div><div class="line"> System. out .println(dbObject);</div><div class="line"> </div><div class="line"> </div><div class="line"> &#125; catch (Exception e) &#123;</div><div class="line"> e.printStackTrace();</div><div class="line"> &#125;</div><div class="line"> &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;读参数除了secondary一共还有五个参数：primary、primaryPreferred、secondary、secondaryPreferred、nearest。</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%89%AF%E6%9C%AC%E9%9B%86/06.png?raw=true" alt=""></figure></p>
<ul>
<li><strong>primary</strong>:默认参数，只从主节点上进行读取操作；</li>
<li><strong>primaryPreferred</strong>:大部分从主节点上读取数据,只有主节点不可用时从secondary节点读取数据。</li>
<li><strong>secondary</strong>:只从secondary节点上进行读取操作，存在的问题是secondary节点的数据会比primary节点数据“旧”。</li>
<li><strong>secondaryPreferred</strong>:优先从secondary节点进行读取操作，secondary节点不可用时从主节点读取数据；</li>
<li><strong>nearest</strong>:不管是主节点、secondary节点，从网络延迟最低的节点上读取数据。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;好，读写分离做好我们可以数据分流，减轻压力解决了“主节点的读写压力过大如何解决？”这个问题。不过当我们的副本节点增多时，主节点的复制压力会加大有什么办法解决吗？mongodb早就有了相应的解决方案。</p>
<p><figure class="figure"><img src="https://github.com/hcldirgit/image/blob/master/%E6%90%AD%E5%BB%BA%E9%AB%98%E5%8F%AF%E7%94%A8mongodb%E9%9B%86%E7%BE%A4%E2%80%94%E2%80%94%20%E5%89%AF%E6%9C%AC%E9%9B%86/07.png?raw=true" alt=""></figure></p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;其中的仲裁节点不存储数据，只是负责故障转移的群体投票，这样就少了数据复制的压力。是不是想得很周到啊，一看mongodb的开发兄弟熟知大数据架构体系，其实不只是主节点、副本节点、仲裁节点，还有Secondary-Only、Hidden、Delayed、Non-Voting。</p>
<ul>
<li><strong>Secondary-Only</strong>:不能成为primary节点，只能作为secondary副本节点，防止一些性能不高的节点成为主节点。</li>
<li><strong>Hidden</strong>:这类节点是不能够被客户端制定IP引用，也不能被设置为主节点，但是可以投票，一般用于备份数据。</li>
<li><strong>Delayed</strong>：可以指定一个时间延迟从primary节点同步数据。主要用于备份数据，如果实时同步，误删除数据马上同步到从节点，恢复又恢复不了。</li>
<li><strong>Non-Voting</strong>：没有选举权的secondary节点，纯粹的备份数据节点。</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;到此整个mongodb副本集搞定了两个问题：</p>
<ul>
<li>主节点挂了能否自动切换连接？目前需要手工切换。</li>
<li>主节点的读写压力过大如何解决？</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;还有这两个问题后续解决：</p>
<ul>
<li>从节点每个上面的数据都是对数据库全量拷贝，从节点压力会不会过大？</li>
<li>数据压力大到机器支撑不了的时候能否做到自动扩展？</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;做了副本集发现又一些问题：</p>
<ul>
<li>副本集故障转移，主节点是如何选举的？能否手动干涉下架某一台主节点。</li>
<li>官方说副本集数量最好是奇数，为什么？</li>
<li>mongodb副本集是如何同步的？如果同步不及时会出现什么情况？会不会出现不一致性？</li>
<li>mongodb的故障转移会不会无故自动发生？什么条件会触发？频繁触发可能会带来系统负载加重</li>
</ul>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;参考：<a href="http://cn.docs.mongodb.org/manual/administration/replica-set-member-configuration/" target="_blank" rel="external">http://cn.docs.mongodb.org/manual/administration/replica-set-member-configuration/</a></p>

	

	

</article>





	<span class="different-posts">📖 <a href="/page/32">more posts</a> 📖</span>



	</main>

	<footer class="footer">
	<div class="footer-content">
		
	      <div class="footer__element">
	<p>Hi there, <br />welcome to my Blog glad you found it. Have a look around, will you?</p>
</div>

	    
	      <div class="footer__element">
	<h5>Check out</h5>
	<ul class="footer-links">
		<li class="footer-links__link"><a href="/archives">Archive</a></li>
		
		  <li class="footer-links__link"><a href="/atom.xml">RSS</a></li>
	    
		<li class="footer-links__link"><a href="/about">about page</a></li>
		<li class="footer-links__link"><a href="/tags">Tags</a></li>
		<li class="footer-links__link"><a href="/categories">Categories</a></li>
	</ul>
</div>

	    

		<div class="footer-credit">
			<span>© 2017 失落的乐章 | Powered by <a href="https://hexo.io/">Hexo</a> | Theme <a href="https://github.com/HoverBaum/meilidu-hexo">MeiliDu</a></span>
		</div>

	</div>


</footer>



</body>

</html>
